Railway Operation Simulator  v2.13.0 Beta
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "Utilities.h"
45 // #include "DisplayUnit.h" included in header file
46 #include "GraphicUnit.h"
47 #include "TextUnit.h"
48 #include "TrainUnit.h"
49 
50 #pragma package(smart_init)
51 // ---------------------------------------------------------------------------
52 
55 
56 // ---------------------------------------------------------------------------
57 
58 // FIXED TRACK :-
59 
60 // Constructor to build TrackPieces from array
61 
62 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
63  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
64 {
65  for(int x = 0; x < 4; x++)
66  {
67  Link[x] = LkVal[x];
68  Config[x] = ConfigVal[x];
69  }
70 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
71  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
72  if(SpeedTagVal == 76)
73  {
75  }
76  else if(SpeedTagVal == 77)
77  {
79  }
80  else if(SpeedTagVal == 78)
81  {
83  }
84  else if(SpeedTagVal == 79)
85  {
87  }
88  else if(SpeedTagVal == 96)
89  {
91  }
92  else if(SpeedTagVal == 129)
93  {
95  }
96  else if(SpeedTagVal == 130)
97  {
99  }
100  else if(SpeedTagVal == 131)
101  {
103  }
104  else if(SpeedTagVal == 145)
105  {
107  }
108  else if(SpeedTagVal == 146)
109  {
111  }
112 }
113 
114 // ---------------------------------------------------------------------------
115 
116 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
117  FixedNamedLocationElement(false) // default values
118 {
119  for(int x = 0; x < 4; x++)
120  {
121  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
122  Config[x] = NotSet;
123  }
124 }
125 
126 // ---------------------------------------------------------------------------
127 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
128 {
129  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
130  AnsiString(VLocInput));
131  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
132  Utilities->CallLogPop(1331);
133 }
134 
135 // ---------------------------------------------------------------------------
136 
137 // VARIABLE TRACK :-
138 
139 // ---------------------------------------------------------------------------
140 
142 {
143  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
144  {
145  return(true);
146  }
147  else
148  {
149  return(false);
150  }
151 }
152 
153 // ---------------------------------------------------------------------------
154 
156 {
157  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
158  {
159  return(true);
160  }
161  else
162  {
163  return(false);
164  }
165 }
166 
167 // ---------------------------------------------------------------------------
168 
170 // 'Variable' in the sense that element might be striped or non-striped
171 {
172  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
173  Graphics::TBitmap *GraphicOutput = GraphicPtr;
174 
175  if(LocationName == "")
176  {
177  switch(SpeedTag)
178  {
179  case 76: // t platform
180  GraphicOutput = RailGraphics->gl76Striped;
181  break;
182 
183  case 77: // h platform
184  GraphicOutput = RailGraphics->bm77Striped;
185  break;
186 
187  case 78: // v platform
188  GraphicOutput = RailGraphics->bm78Striped;
189  break;
190 
191  case 79: // r platform
192  GraphicOutput = RailGraphics->gl79Striped;
193  break;
194 
195  case 96: // concourse
196  GraphicOutput = RailGraphics->ConcourseStriped;
197  break;
198 
199  case 129: // v footbridge
200  GraphicOutput = RailGraphics->gl129Striped;
201  break;
202 
203  case 130: // h footbridge
204  GraphicOutput = RailGraphics->gl130Striped;
205  break;
206 
207  case 131: // non-station named loc
208  GraphicOutput = RailGraphics->bmNameStriped;
209  break;
210 
211  case 145: // v underpass
212  GraphicOutput = RailGraphics->gl145Striped;
213  break;
214 
215  case 146: // h underpass
216  GraphicOutput = RailGraphics->gl146Striped;
217  break;
218 
219  default:
220  GraphicOutput = GraphicPtr;
221  break;
222  }
223  }
224  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
225  Utilities->CallLogPop(1332);
226 }
227 
228 // ---------------------------------------------------------------------------
229 
230 AnsiString TTrackElement::LogTrack(int Caller) const
231 // for debugging when passes as a call parameter
232 {
233  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
234  AnsiString(TrainIDOnBridgeTrackPos01) + "," + AnsiString(TrainIDOnBridgeTrackPos23) + ",EndTrkEl,";
235 
236  return(LogString);
237 }
238 
239 // ---------------------------------------------------------------------------
240 
242  TTrackElement::TTrackElement(TFixedTrackPiece Input) : TFixedTrackPiece(Input), HLoc(-2000000000), VLoc(-2000000000), LocationName(""), ActiveTrackElementName(""),
243  Attribute(0), CallingOnSet(false), Length01(Track->DefaultTrackLength), Length23(-1), SpeedLimit01(Track->DefaultTrackSpeedLimit), SpeedLimit23(-1),
244  TrainIDOnElement(-1), TrainIDOnBridgeTrackPos01(-1), TrainIDOnBridgeTrackPos23(-1), StationEntryStopLinkPos1(-1), StationEntryStopLinkPos2(-1),
245  SigAspect(FourAspect)
246  {
247  for(int x = 0; x < 4; x++)
248  {
249  ConnLinkPos[x] = -1;
250  Conn[x] = -1;
251  }
252  if((TrackType == Points) || (TrackType == Crossover) || (TrackType == Bridge))
253  {
256  }
257  }
258 
259 // ---------------------------------------------------------------------------
260 
261 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
262 {
263  if(lower.second < higher.second)
264  {
265  return(true);
266  }
267  else if(lower.second > higher.second)
268  {
269  return(false);
270  }
271  else if(lower.second == higher.second)
272  {
273  if(lower.first < higher.first)
274  {
275  return(true);
276  }
277  }
278  return(false);
279 }
280 
281 // ---------------------------------------------------------------------------
282 // PrefDirElement Functions
283 // ---------------------------------------------------------------------------
284 
285 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
286  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
287  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
288 {
289  if(!EntryExitNumber())
290  {
291  throw Exception("EXNumber failure in TPrefDirElement constructor");
292  }
295 }
296 
297 // ---------------------------------------------------------------------------
298 
299 AnsiString TPrefDirElement::LogPrefDir() const
300 // for debugging when passed as a call parameter
301 {
302  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
303  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
304  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeTrackPos01) + "," +
305  AnsiString(TrainIDOnBridgeTrackPos23);
306 
307 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
308  return(LogString);
309 }
310 
311 // ---------------------------------------------------------------------------
312 
313 bool TPrefDirElement::EntryExitNumber() // true for valid number
314 /*
315  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
316  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
317  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
318  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
319  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
320  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
321  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
322  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
323  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
324 */
325 
326 {
327  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
328  int EXArray[16][2] =
329  {{4, 6}, {2, 8}, // horizontal & vertical
330  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
331  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
332  {1, 9}, {3, 7}}; // forward & reverse diagonals
333 
334  int EXNum = -1;
335  int Entry, Exit;
336 
337  if(ELink > -1)
338  {
339  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
340  }
341  else if(Link[2] == -1)
342  {
343  Entry = Link[0];
344  }
345  else
346  {
347  Utilities->CallLogPop(122);
348  return(false);
349  }
350  if(XLink > -1)
351  {
352  Exit = XLink;
353  }
354  else if(Link[2] == -1)
355  {
356  Exit = Link[1];
357  }
358  else
359  {
360  Utilities->CallLogPop(123);
361  return(false);
362  }
363  for(int x = 0; x < 16; x++)
364  {
365  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
366  {
367  EXNum = x;
368  }
369  }
370  if(EXNum == -1)
371  {
372  Utilities->CallLogPop(124);
373  return(false);
374  }
375  int BrNum = -1;
376 
377 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
378  the graphic for each of which is different because of the shape of the overbridge. The basic
379  entry/exit value is computed above, and this used to select only from elements with that entry/exit
380  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
381  int BrEXArray[24][2] = {
382  {4,6},{2,8},{1,9},{3,7},
383  {1,9},{3,7},{1,9},{3,7},
384  {2,8},{4,6},{2,8},{4,6}
385 */
386 
387  if(TrackType == Bridge)
388  {
389  if(EXNum == 1)
390  {
391  if(SpeedTag == 49)
392  {
393  BrNum = 1 + 16;
394  }
395  else if(SpeedTag == 54)
396  {
397  BrNum = 8 + 16;
398  }
399  else if(SpeedTag == 55)
400  {
401  BrNum = 10 + 16;
402  }
403  }
404  else if(EXNum == 0)
405  {
406  if(SpeedTag == 48)
407  {
408  BrNum = 0 + 16;
409  }
410  else if(SpeedTag == 58)
411  {
412  BrNum = 11 + 16;
413  }
414  else if(SpeedTag == 59)
415  {
416  BrNum = 9 + 16;
417  }
418  }
419  else if(EXNum == 14)
420  {
421  if(SpeedTag == 50)
422  {
423  BrNum = 2 + 16;
424  }
425  else if(SpeedTag == 52)
426  {
427  BrNum = 4 + 16;
428  }
429  else if(SpeedTag == 57)
430  {
431  BrNum = 6 + 16;
432  }
433  }
434  else if(EXNum == 15)
435  {
436  if(SpeedTag == 51)
437  {
438  BrNum = 3 + 16;
439  }
440  else if(SpeedTag == 53)
441  {
442  BrNum = 7 + 16;
443  }
444  else if(SpeedTag == 56)
445  {
446  BrNum = 5 + 16;
447  }
448  }
449  }
450  if(BrNum == -1)
451  {
452  EXNumber = EXNum;
453  }
454  else
455  {
456  EXNumber = BrNum;
457  }
458  Utilities->CallLogPop(125);
459  return(true);
460 }
461 
462 // ---------------------------------------------------------------------------
463 
465 /*
466  This is the basic track graphic for use in plotting the original graphic during route flashing.
467  Enter with all set apart from EXGraphic & EntryDirectionGraphic
468 */
469 {
470  if(SpeedTag == 64)
471  {
472  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
473 
474  }
475  if(SpeedTag == 65)
476  {
477  return(RailGraphics->LinkGraphicsPtr[17]);
478  }
479  if(SpeedTag == 66)
480  {
481  return(RailGraphics->LinkGraphicsPtr[18]);
482  }
483  if(SpeedTag == 67)
484  {
485  return(RailGraphics->LinkGraphicsPtr[19]);
486  }
487  if(SpeedTag == 80)
488  {
489  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
490 
491  }
492  if(SpeedTag == 81)
493  {
494  return(RailGraphics->LinkGraphicsPtr[21]);
495  }
496  if(SpeedTag == 82)
497  {
498  return(RailGraphics->LinkGraphicsPtr[22]);
499  }
500  if(SpeedTag == 83)
501  {
502  return(RailGraphics->LinkGraphicsPtr[23]);
503  }
504  if(SpeedTag == 84)
505  {
506  return(RailGraphics->LinkGraphicsPtr[24]);
507  }
508  if(SpeedTag == 85)
509  {
510  return(RailGraphics->LinkGraphicsPtr[25]);
511  }
512  if(SpeedTag == 86)
513  {
514  return(RailGraphics->LinkGraphicsPtr[26]);
515  }
516  if(SpeedTag == 87)
517  {
518  return(RailGraphics->LinkGraphicsPtr[27]);
519  }
520  if(SpeedTag == 129)
521  {
522  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
523 
524  }
525  if(SpeedTag == 130)
526  {
527  return(RailGraphics->LinkGraphicsPtr[29]);
528  }
529  if(XLinkPos == -1) // not set, could be first element or last element = leading point
530  {
531 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
532 // Points & don't want to display these)
533  if(Link[2] != -1)
534  {
535  return(0); // i.e. complex element, don't display
536  }
537  else
538  {
539  if(!EntryExitNumber())
540  {
541  throw Exception("Error in EntryExitNumber 4");
542  }
543  else
544  {
546  }
547  }
548  }
549  if(EXNumber > 15) // underbridge
550  {
551  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
552  }
553  else
554  {
556  }
557 }
558 
559 // ---------------------------------------------------------------------------
560 
562 /*
563  As above but for PrefDir graphics.
564 */
565 {
566  if(SpeedTag == 64)
567  {
568  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
569 
570  }
571  if(SpeedTag == 65)
572  {
574  }
575  if(SpeedTag == 66)
576  {
578  }
579  if(SpeedTag == 67)
580  {
582  }
583  if(SpeedTag == 80)
584  {
585  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
586 
587  }
588  if(SpeedTag == 81)
589  {
591  }
592  if(SpeedTag == 82)
593  {
595  }
596  if(SpeedTag == 83)
597  {
599  }
600  if(SpeedTag == 84)
601  {
603  }
604  if(SpeedTag == 85)
605  {
607  }
608  if(SpeedTag == 86)
609  {
611  }
612  if(SpeedTag == 87)
613  {
615  }
616  if(SpeedTag == 129)
617  {
618  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
619 
620  }
621  if(SpeedTag == 130)
622  {
624  }
625  if(XLinkPos == -1) // not set, could be first element or last element = leading point
626  {
627 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
628  if(Link[2] != -1)
629  {
630  return(0); // i.e. complex element, don't display
631  }
632  else
633  {
634  if(!EntryExitNumber())
635  {
636  throw Exception("Error in EntryExitNumber 5");
637  }
638  else
639  {
641  }
642  }
643  }
644  if(EXNumber > 15) // underbridge
645  {
647  }
648  else
649  {
651  }
652 }
653 
654 // ---------------------------------------------------------------------------
655 
656 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
657 /*
658  As above but for route graphics.
659 */
660 {
661  if(!AutoSigsFlag && !PrefDirRoute)
662  {
663  if(SpeedTag == 64)
664  {
665  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
666 
667  }
668  if(SpeedTag == 65)
669  {
671  }
672  if(SpeedTag == 66)
673  {
675  }
676  if(SpeedTag == 67)
677  {
679  }
680  if(SpeedTag == 80)
681  {
682  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
683 
684  }
685  if(SpeedTag == 81)
686  {
688  }
689  if(SpeedTag == 82)
690  {
692  }
693  if(SpeedTag == 83)
694  {
696  }
697  if(SpeedTag == 84)
698  {
700  }
701  if(SpeedTag == 85)
702  {
704  }
705  if(SpeedTag == 86)
706  {
708  }
709  if(SpeedTag == 87)
710  {
712  }
713  if(SpeedTag == 129)
714  {
715  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
716 
717  }
718  if(SpeedTag == 130)
719  {
721  }
722  if(XLinkPos == -1) // not set, could be first element or last element = leading point
723  {
724  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
725  if(Link[2] != -1)
726  {
727  return(0); // i.e. complex element, don't display
728  }
729  else
730  {
731  if(!EntryExitNumber())
732  {
733  throw Exception("Error in EntryExitNumber 6");
734  }
735  else
736  {
738  }
739  }
740  }
741  if(EXNumber > 15) // underbridge
742  {
744  }
745  else
746  {
748  }
749  }
750 
751  else if(!AutoSigsFlag && PrefDirRoute)
752  {
753  if(SpeedTag == 64)
754  {
755  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
756 
757  }
758  if(SpeedTag == 65)
759  {
761  }
762  if(SpeedTag == 66)
763  {
765  }
766  if(SpeedTag == 67)
767  {
769  }
770  if(SpeedTag == 80)
771  {
772  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
773 
774  }
775  if(SpeedTag == 81)
776  {
778  }
779  if(SpeedTag == 82)
780  {
782  }
783  if(SpeedTag == 83)
784  {
786  }
787  if(SpeedTag == 84)
788  {
790  }
791  if(SpeedTag == 85)
792  {
794  }
795  if(SpeedTag == 86)
796  {
798  }
799  if(SpeedTag == 87)
800  {
802  }
803  if(SpeedTag == 129)
804  {
805  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
806 
807  }
808  if(SpeedTag == 130)
809  {
811  }
812  if(XLinkPos == -1) // not set, could be first element or last element = leading point
813  {
814  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
815  if(Link[2] != -1)
816  {
817  return(0); // i.e. complex element, don't display
818  }
819  else
820  {
821  if(!EntryExitNumber())
822  {
823  throw Exception("Error in EntryExitNumber 10");
824  }
825  else
826  {
828  }
829  }
830  }
831  if(EXNumber > 15) // underbridge
832  {
834  }
835  else
836  {
838  }
839  }
840 
841  else
842  {
843  if(SpeedTag == 64)
844  {
845  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
846 
847  }
848  if(SpeedTag == 65)
849  {
851  }
852  if(SpeedTag == 66)
853  {
855  }
856  if(SpeedTag == 67)
857  {
859  }
860  if(SpeedTag == 80)
861  {
862  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
863 
864  }
865  if(SpeedTag == 81)
866  {
868  }
869  if(SpeedTag == 82)
870  {
872  }
873  if(SpeedTag == 83)
874  {
876  }
877  if(SpeedTag == 84)
878  {
880  }
881  if(SpeedTag == 85)
882  {
884  }
885  if(SpeedTag == 86)
886  {
888  }
889  if(SpeedTag == 87)
890  {
892  }
893  if(SpeedTag == 129)
894  {
895  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
896 
897  }
898  if(SpeedTag == 130)
899  {
901  }
902  if(XLinkPos == -1) // not set, could be first element or last element = leading point
903  {
904  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
905  if(Link[2] != -1)
906  {
907  return(0); // i.e. complex element, don't display
908  }
909  else
910  {
911  if(!EntryExitNumber())
912  {
913  throw Exception("Error in EntryExitNumber 11");
914  }
915  else
916  {
918  }
919  }
920  }
921  if(EXNumber > 15) // underbridge
922  {
924  }
925  else
926  {
928  }
929  }
930 }
931 
932 // ---------------------------------------------------------------------------
933 
935 /*
936  As above but for route flashing graphics. (Disused - now combined with above)
937 */
938 {
939  if(SpeedTag == 64)
940  {
941  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
942 
943  }
944  if(SpeedTag == 65)
945  {
947  }
948  if(SpeedTag == 66)
949  {
951  }
952  if(SpeedTag == 67)
953  {
955  }
956  if(SpeedTag == 80)
957  {
958  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
959 
960  }
961  if(SpeedTag == 81)
962  {
964  }
965  if(SpeedTag == 82)
966  {
968  }
969  if(SpeedTag == 83)
970  {
972  }
973  if(SpeedTag == 84)
974  {
976  }
977  if(SpeedTag == 85)
978  {
980  }
981  if(SpeedTag == 86)
982  {
984  }
985  if(SpeedTag == 87)
986  {
988  }
989  if(SpeedTag == 129)
990  {
991  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
992 
993  }
994  if(SpeedTag == 130)
995  {
997  }
998  if(XLinkPos == -1) // not set, could be first element or last element = leading point
999  {
1000 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
1001  if(Link[2] != -1)
1002  {
1003  return(0); // i.e. complex element, don't display
1004  }
1005  else
1006  {
1007  if(!EntryExitNumber())
1008  {
1009  throw Exception("Error in EntryExitNumber 7");
1010  }
1011  else
1012  {
1014  }
1015  }
1016  }
1017  if(EXNumber > 15) // underbridge
1018  {
1020  }
1021  else
1022  {
1024  }
1025 }
1026 
1027 // ---------------------------------------------------------------------------
1028 
1030 /*
1031  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1032 */
1033 {
1034  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1035  {
1037  }
1038  else
1039  {
1040  throw Exception("Error in EntryExitNumber 8");
1041  }
1042 }
1043 
1044 // ---------------------------------------------------------------------------
1045 
1046 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1047 /*
1048  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1049 */
1050 {
1051  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1052  {
1053  if(!AutoSigsFlag && !PrefDirRoute)
1054  {
1056  }
1057  else if(!AutoSigsFlag && PrefDirRoute)
1058  {
1060  }
1061  else
1062  {
1064  }
1065  }
1066  else
1067  {
1068  throw Exception("Error in EntryExitNumber 9");
1069  }
1070 }
1071 
1072 // ---------------------------------------------------------------------------
1073 
1075 /*
1076  Set == operator when TrackVectorPosition, ELink & XLink all same
1077 */
1078 {
1079  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1080  {
1081  return(true);
1082  }
1083  else
1084  {
1085  return(false);
1086  }
1087 }
1088 
1089 // ---------------------------------------------------------------------------
1090 
1092 /*
1093  Set != operator when any of TrackVectorPosition, ELink or XLink different
1094 */
1095 {
1096  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1097  {
1098  return(false);
1099  }
1100  else
1101  {
1102  return(true);
1103  }
1104 }
1105 
1106 // ---------------------------------------------------------------------------
1107 // Track functions
1108 // ---------------------------------------------------------------------------
1109 
1110 // ---------------------------------------------------------------------------
1111 
1112 TTrack::TActiveLevelCrossing::TActiveLevelCrossing()
1113 {
1114  TypeOfRoute = 0;
1115  ReducedTimePenalty = false;
1116  BarrierState = Up;
1117  ChangeDuration = 0.0;
1118  BaseElementSpeedTag = 1;
1119  HLoc = 0;
1120  VLoc = 0;
1121  StartTime = TDateTime(0);
1122 }
1123 
1124 // ---------------------------------------------------------------------------
1125 
1127 {
1128 // CurrentSpeedButtonTag = 0; //not assigned yet
1129 
1130  HLocMin = 2000000000;
1131  VLocMin = 2000000000;
1132  HLocMax = -2000000000;
1133  VLocMax = -2000000000;
1134  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1135  CopyFlag = false; // only true for copying, so names aren't copied
1136  AnsiString NL = '\n';
1137 
1138  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable; " + NL + NL +
1139  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1140  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1141  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1142 
1147 
1148  int InternalLinkCheckArray[9][2] =
1149  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1150 
1151 /* array of valid link values for 'old' location and 'new' location, where
1152  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1153 
1154  for(int x = 0; x < 9; x++)
1155  {
1156  for(int y = 0; y < 2; y++)
1157  {
1158  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1159  }
1160  }
1161 
1162 // Platform and default track element values
1163  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1164 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1165  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1166  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1167  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1168  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, crossovers, bridges, gaps,
1169  << 60 << 61 << 62 << 63 << 68 << 69 << 70 << 71 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
1170  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
1171  // elements, & can always use straights so leave out.) Allow horiz & vert signals as from v2.6.0
1172  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1173 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1174 
1175  int HVArray[10][2] =
1176  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1177 
1178  for(int x = 0; x < 10; x++)
1179  {
1180  for(int y = 0; y < 2; y++)
1181  {
1182  LinkHVArray[x][y] = HVArray[x][y];
1183  }
1184  }
1185  TrackFinished = false;
1186 // DistancesSet = false;
1187 
1188  TSigElement TempSigTable[40] = // original four aspect
1189  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1190  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1191 
1192  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1193  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1194 
1197 
1198  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1199  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1200 
1201  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1202  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1203  {75, 4, RailGraphics->gl75}};
1204 
1205  for(int x = 0; x < 40; x++)
1206  {
1207  SigTable[x] = TempSigTable[x];
1208  }
1209 
1210  TSigElement TempSigTableThreeAspect[40] =
1211  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1212  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1213 
1214  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1215  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1216 
1217  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1218  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1219 
1220  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1221  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1222 
1223  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1224  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1225  {75, 4, RailGraphics->gl75}};
1226 
1227  for(int x = 0; x < 40; x++)
1228  {
1229  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1230  }
1231 
1232  TSigElement TempSigTableTwoAspect[40] =
1233  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1234  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1235 
1236  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1237  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1238 
1239  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1240  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1241 
1242  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1243  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1244 
1245  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1246  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1247  {75, 4, RailGraphics->gl75}};
1248 
1249  for(int x = 0; x < 40; x++)
1250  {
1251  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1252  }
1253 
1254  TSigElement TempSigTableGroundSignal[40] =
1258 
1262 
1266 
1270 
1271  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1274 
1275  for(int x = 0; x < 40; x++)
1276  {
1277  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1278  }
1279 
1280 /*
1281  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1282  a single location. These are as follows:-
1283  Directly Adjacent = up, down, left or right - NOT diagonal.
1284  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1285  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1286  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1287 
1288  //t 76
1289  //b 77
1290  //l 78
1291  //r 79
1292  //c 96
1293  //v fb 129
1294  //h fb 130
1295  //v underpass 145
1296  //h underpass 146
1297  //n 131
1298 */
1299 
1300  int Tag76[25][3] =
1301  {{-1, 0, 96}, // c top plat
1302  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1303  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1304  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1305  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1306  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1307  {0, 0, 129}, {0, -1, 145}, // v up
1308  {0, 0, 145}};
1309 
1310  for(int x = 0; x < 25; x++)
1311  {
1312  for(int y = 0; y < 3; y++)
1313  {
1314  Tag76Array[x][y] = Tag76[x][y];
1315  }
1316  }
1317 
1318  int Tag77[25][3] =
1319  {{-1, 0, 96}, // c bot plat
1320  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1321  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1322  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1323  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1324  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1325  {0, 0, 129}, {0, 1, 145}, // v up
1326  {0, 0, 145}};
1327 
1328  for(int x = 0; x < 25; x++)
1329  {
1330  for(int y = 0; y < 3; y++)
1331  {
1332  Tag77Array[x][y] = Tag77[x][y];
1333  }
1334  }
1335 
1336  int Tag78[25][3] =
1337  {{-1, 0, 96}, // c left plat
1338  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1339  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1340  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1341  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1342  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1343  {0, 0, 130}, {-1, 0, 146}, // h up
1344  {0, 0, 146}};
1345 
1346  for(int x = 0; x < 25; x++)
1347  {
1348  for(int y = 0; y < 3; y++)
1349  {
1350  Tag78Array[x][y] = Tag78[x][y];
1351  }
1352  }
1353 
1354  int Tag79[25][3] =
1355  {{-1, 0, 96}, // c right plat
1356  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1357  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1358  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1359  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1360  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1361  {0, 0, 130}, {1, 0, 146}, // h up
1362  {0, 0, 146}};
1363 
1364  for(int x = 0; x < 25; x++)
1365  {
1366  for(int y = 0; y < 3; y++)
1367  {
1368  Tag79Array[x][y] = Tag79[x][y];
1369  }
1370  }
1371 
1372  int Tag96[28][3] =
1373  {{-1, 0, 96}, // c //concourse
1374  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1375  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1376  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1377  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1378  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1379  {0, -1, 129}, {1, 0, 130}, // h fb
1380  {-1, 0, 130}, {0, 1, 145}, // v up
1381  {0, -1, 145}, {1, 0, 146}, // h up
1382  {-1, 0, 146}};
1383 
1384  for(int x = 0; x < 28; x++)
1385  {
1386  for(int y = 0; y < 3; y++)
1387  {
1388  Tag96Array[x][y] = Tag96[x][y];
1389  }
1390  }
1391 
1392  int Tag129[8][3] = // vert fb
1393  {{0, -1, 96}, // c
1394  {0, -1, 77}, // b
1395  {0, -1, 129}, // v fb
1396 
1397  {0, 1, 96}, // c
1398  {0, 1, 76}, // t
1399  {0, 1, 129}, // v fb
1400 
1401  {0, 0, 76}, // t
1402  {0, 0, 77}}; // b
1403 
1404  for(int x = 0; x < 8; x++)
1405  {
1406  for(int y = 0; y < 3; y++)
1407  {
1408  Tag129Array[x][y] = Tag129[x][y];
1409  }
1410  }
1411 
1412  int Tag145[8][3] = // vert up
1413  {{0, -1, 96}, // c
1414  {0, -1, 77}, // b
1415  {0, -1, 145}, // v fb
1416 
1417  {0, 1, 96}, // c
1418  {0, 1, 76}, // t
1419  {0, 1, 145}, // v fb
1420 
1421  {0, 0, 76}, // t
1422  {0, 0, 77}}; // b
1423 
1424  for(int x = 0; x < 8; x++)
1425  {
1426  for(int y = 0; y < 3; y++)
1427  {
1428  Tag145Array[x][y] = Tag145[x][y];
1429  }
1430  }
1431 
1432  int Tag130[8][3] = // hor fb
1433  {{-1, 0, 96}, // c
1434  {-1, 0, 79}, // r
1435  {-1, 0, 130}, // h fb
1436 
1437  {1, 0, 96}, // c
1438  {1, 0, 78}, // l
1439  {1, 0, 130}, // h fb
1440 
1441  {0, 0, 78}, // l
1442  {0, 0, 79}}; // r
1443 
1444  for(int x = 0; x < 8; x++)
1445  {
1446  for(int y = 0; y < 3; y++)
1447  {
1448  Tag130Array[x][y] = Tag130[x][y];
1449  }
1450  }
1451 
1452  int Tag146[8][3] = // hor up
1453  {{-1, 0, 96}, // c
1454  {-1, 0, 79}, // r
1455  {-1, 0, 146}, // h fb
1456 
1457  {1, 0, 96}, // c
1458  {1, 0, 78}, // l
1459  {1, 0, 146}, // h fb
1460 
1461  {0, 0, 78}, // l
1462  {0, 0, 79}}; // r
1463 
1464  for(int x = 0; x < 8; x++)
1465  {
1466  for(int y = 0; y < 3; y++)
1467  {
1468  Tag146Array[x][y] = Tag146[x][y];
1469  }
1470  }
1471 
1472  int Tag131[4][3] =
1473  {{-1, 0, 131}, // n
1474  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1475 
1476  for(int x = 0; x < 4; x++)
1477  {
1478  for(int y = 0; y < 3; y++)
1479  {
1480  Tag131Array[x][y] = Tag131[x][y];
1481  }
1482  }
1483 
1484  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1485  {
1486  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1487  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1488  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1489  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1490  140, 144, 145, 146
1491  };
1492 
1493  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1494  {
1495  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1496  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1497  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1498  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1499  141, 144, 145, 146
1500  };
1501 
1502  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1503  {
1504  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1505  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1506  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1507  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1508  141, 144, 146, 145
1509  };
1510 
1511  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1512  {
1513  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1514  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1515  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1516  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1517  140, 144, 146, 145
1518  };
1519 
1520  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1521  {
1522  FlipArray[x] = InternalFlipArray[x];
1523  MirrorArray[x] = InternalMirrorArray[x];
1524  RotRightArray[x] = InternalRotRightArray[x];
1525  RotLeftArray[x] = InternalRotLeftArray[x];
1526  }
1527 }
1528 
1529 // ---------------------------------------------------------------------------
1531 {
1532 // delete TrackVectorPtr;
1533 // delete FixedTrackArrayPtr;
1534  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1535 
1536  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1537  {
1538  delete UGMIt->second;
1539  UGMIt++;
1540  }
1541  delete GapFlashGreen;
1542  delete GapFlashRed;
1543  // all the rest are cleared by the relevant automatic destructors
1544 }
1545 
1546 // ---------------------------------------------------------------------------
1547 
1549 {
1550  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1551  {
1552 // loc 0 not used, set to bmSolidBgnd
1556 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1576  };
1577 
1578  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1579  {
1580 // loc 0 not used, set to smSolidBgnd
1584 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1603  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1604  };
1605 
1606 // track types
1607  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1608  {
1609  Erase, // 1 0
1610  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1611  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1612  Crossover, Crossover, // 2 15-16
1613  Unused, // 17 (was for text in earlier development) //1 17
1616  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1620  Platform, Platform, Platform, Platform, // 4 76-79
1623  Concourse, // 1 96
1626  Simple, Simple, Simple, Simple, // 4 125-128
1627  FootCrossing, FootCrossing, // 2 129-130
1628  NamedNonStationLocation, // 1 131
1629  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1630  Simple, Simple, Simple, Simple, // 4 140-143
1631  LevelCrossing, // 1 144
1632  FootCrossing, FootCrossing // 2 145 & 146
1633  };
1634 
1635 // links
1636  int Links[FirstUnusedSpeedTagNumber][4] =
1637  {{-1, -1, -1, -1}, // erase element
1638  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1639  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1640 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1641  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1642  {-1, -1, -1, -1}, // unused
1643  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1644  {2, 7, -1, -1}, // simple
1645  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1646 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1647 // (or right diverging if no straight)
1648  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1649  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1650  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1651  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1652  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1653  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1654  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1655  {-1, -1, -1, -1}, // Concourse
1656  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1657  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1658  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1659  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1660  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1661  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1662  {-1, -1, -1, -1}, // NamedNonStationLocation
1663  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1664 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1665  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1666  {-1, -1, -1, -1}, // level crossing
1667  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1668  };
1669 
1671  {{NotSet, NotSet, NotSet, NotSet}, // unused
1675  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1677  {NotSet, NotSet, NotSet, NotSet}, // unused
1681  {Connection, Connection, NotSet, NotSet}, // simple
1685  {Lead, Trail, Lead, Trail}, // points
1687  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1695  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1701  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1710  {Connection, Connection, NotSet, NotSet}, // Arrows
1712  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1714  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1716  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1717  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1718  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1719  };
1720 
1721  for(int x = 0; x < 17; x++)
1722  {
1723  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1724  }
1725  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1726 // 17 was the old text value so don't want any graphics (now disused)
1727  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1728  {
1729  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1730  }
1731 }
1732 
1733 // ---------------------------------------------------------------------------
1734 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1735  ExistingGraphicLoaded(false), Width(16), Height(16)
1736 {
1737  OriginalGraphic = new Graphics::TBitmap;
1738  OriginalGraphic->PixelFormat = pf8bit;
1739  OriginalGraphic->Width = Width;
1740  OriginalGraphic->Height = Height;
1741  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1742 }
1743 
1744 // ---------------------------------------------------------------------------
1745 
1746 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1747  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1748 {
1749  OriginalGraphic = new Graphics::TBitmap;
1750  OriginalGraphic->PixelFormat = pf8bit;
1751  OriginalGraphic->Width = Width;
1752  OriginalGraphic->Height = Height;
1753  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1754 }
1755 
1756 // ---------------------------------------------------------------------------
1757 
1759 {
1760  delete OriginalGraphic;
1761 }
1762 
1763 // ---------------------------------------------------------------------------
1764 
1765 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1766 {
1767  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1768  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1769  VPos = VPosIn;
1770  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1771 
1772  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1773  SourceRect.init(Left, Top, Left + Width, Top + Height);
1774  ScreenSourceSet = true;
1775  Utilities->CallLogPop(422);
1776 }
1777 
1778 // ---------------------------------------------------------------------------
1779 
1781 {
1782  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1783  if(!OverlayLoaded)
1784  {
1785  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1786  }
1787  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1788  {
1789  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1790  }
1791  if(!ScreenSourceSet)
1792  {
1793  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1794  }
1795  if(ExistingGraphicLoaded) // can only call one of the load functions
1796  {
1797  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1798  }
1799  if(OverlayPlotted) // don't load from screen if overlay plotted
1800  {
1801  Utilities->CallLogPop(775);
1802  return;
1803  }
1804  TRect DestRect(0, 0, Width, Height);
1805 
1807  OriginalLoaded = true;
1808  ScreenGraphicLoaded = true;
1809  Utilities->CallLogPop(423);
1810 }
1811 
1812 // ---------------------------------------------------------------------------
1813 
1814 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1815 /*
1816  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1817 */
1818 {
1819  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1820  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1821  if(!OverlayLoaded)
1822  {
1823  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1824  }
1825  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1826  {
1827  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1828  }
1829  if(ScreenGraphicLoaded) // can only call one of the load functions
1830  {
1831  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1832  }
1833  Width = WidthIn;
1834  Height = HeightIn;
1835  OriginalGraphic->Width = Width;
1836  OriginalGraphic->Height = Height;
1837  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1838  VPos += VOffset;
1839  TRect DestRect(0, 0, Width, Height);
1840 
1841  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1842  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1843  OriginalLoaded = true;
1844  ExistingGraphicLoaded = true;
1845  Utilities->CallLogPop(424);
1846 }
1847 
1848 // ---------------------------------------------------------------------------
1849 
1850 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1851 {
1852  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1853  OverlayGraphic = Overlay;
1854  OverlayLoaded = true;
1855  Utilities->CallLogPop(425);
1856 }
1857 
1858 // ---------------------------------------------------------------------------
1859 
1861 {
1862  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1863  if(!OverlayLoaded)
1864  {
1865  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1866  }
1867  if(!OverlayPlotted)
1868  {
1869  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1870  Disp->Update();
1871  OverlayPlotted = true;
1872  }
1873  Utilities->CallLogPop(426);
1874 }
1875 
1876 // ---------------------------------------------------------------------------
1877 
1879 {
1880  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1881  if(OverlayPlotted)
1882  {
1883  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1884  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1885  {
1886  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1887  }
1888  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1889  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1890  OverlayPlotted = false;
1891  }
1892  Utilities->CallLogPop(427);
1893 }
1894 
1895 // ---------------------------------------------------------------------------
1896 
1898 {
1899  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1900  bool TrackPresent = false;
1901 
1902  if(InactiveTrackVector.size() != 0)
1903  {
1904  Utilities->CallLogPop(1333);
1905  return(false);
1906  }
1907  else if(TrackVector.size() == 0)
1908  {
1909  Utilities->CallLogPop(1334);
1910  return(true);
1911  }
1912  else
1913  {
1914  for(unsigned int x = 0; x < TrackVector.size(); x++)
1915  {
1916  if((TrackElementAt(1042, x).SpeedTag != 0))
1917  {
1918  TrackPresent = true;
1919  }
1920  }
1921  }
1922  Utilities->CallLogPop(1335);
1923  return(!TrackPresent);
1924 }
1925 
1926 // ---------------------------------------------------------------------------
1927 
1928 bool TTrack::NoActiveTrack(int Caller)
1929 {
1930  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1931  bool TrackPresent = false;
1932 
1933  if(TrackVector.size() == 0)
1934  {
1935  Utilities->CallLogPop(1582);
1936  return(true);
1937  }
1938  else
1939  {
1940  for(unsigned int x = 0; x < TrackVector.size(); x++)
1941  {
1942  if((TrackElementAt(1043, x).SpeedTag != 0))
1943  {
1944  TrackPresent = true;
1945  }
1946  break;
1947  }
1948  }
1949  Utilities->CallLogPop(1583);
1950  return(!TrackPresent);
1951 }
1952 
1953 // ---------------------------------------------------------------------------
1954 
1955 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
1956 {
1957  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
1958  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1959  TrackEraseSuccessfulFlag = false;
1960 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
1961 // since have to match platforms as well as track
1962 // used to set TrackFinished to false if an element erased
1963 
1964  ErasedTrackVectorPosition = -1; // marker for no element erased
1965  AnsiString SName = "", ErrorString;
1967  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
1968  TTrackMapIterator TrackMapPtr;
1969  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
1970 
1971  if(TrackVector.size() != 0)
1972  {
1973  TrackMapKeyPair.first = HLocInput;
1974  TrackMapKeyPair.second = VLocInput;
1975  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
1976  if(TrackMapPtr != TrackMap.end())
1977  {
1978  bool FoundFlag;
1979  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
1980  if(FoundFlag) // should find it as it's in the map
1981  {
1982  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
1983  {
1984  SName = TrackElementAt(1, VecPos).LocationName;
1985  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
1986  if(ErrorString != "")
1987  {
1988  throw Exception(ErrorString + " for EraseTrackElement 1");
1989  }
1990  LocationNameMultiMap.erase(SNIt);
1991  }
1992  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
1993  // ensure erase vector element before map element as iterator no longer valid after a map erase
1994  TrackMap.erase(TrackMapPtr);
1995  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
1996  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1998  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
1999  if(SName != "")
2000  {
2001  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2002  int HPos, VPos;
2003  if(TextHandler->FindText(1, SName, HPos, VPos))
2004  {
2005  if(TextHandler->TextErase(5, HPos, VPos, SName))
2006  {
2007  ;
2008  } // condition not used
2009 
2010  }
2011  }
2012  ErasedTrackVectorPosition = VecPos;
2013  TrackEraseSuccessfulFlag = true;
2014  }
2015  }
2016  }
2017  if(InactiveTrackVector.size() != 0)
2018  {
2019  unsigned int VecPos;
2020  InactiveTrackMapKeyPair.first = HLocInput;
2021  InactiveTrackMapKeyPair.second = VLocInput;
2022  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2023  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2024  {
2025  SName = "";
2026  VecPos = InactiveTrack2MultiMapIterator->second;
2027  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2028  {
2029  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2030  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2031  if(ErrorString != "")
2032  {
2033  throw Exception(ErrorString + " for EraseTrackElement 2A");
2034  }
2035  LocationNameMultiMap.erase(SNIt);
2036  }
2037  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2038  // ensure erase vector element before map element as iterator no longer valid after a map erase
2039  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2040  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2041  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2043  TrackEraseSuccessfulFlag = true;
2044  if(SName != "")
2045  {
2046  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2047  int HPos, VPos;
2048  if(TextHandler->FindText(2, SName, HPos, VPos))
2049  {
2050  if(TextHandler->TextErase(6, HPos, VPos, SName))
2051  {
2052  ;
2053  } // condition not used
2054 
2055  }
2056  }
2057  }
2058  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2059  {
2060  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2061  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2062  {
2063  SName = "";
2064  VecPos = InactiveTrack2MultiMapIterator->second;
2065  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2066  {
2067  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2068  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2069  if(ErrorString != "")
2070  {
2071  throw Exception(ErrorString + " for EraseTrackElement 2B");
2072  }
2073  LocationNameMultiMap.erase(SNIt);
2074  }
2075  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2076  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2077  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2079  if(SName != "")
2080  {
2081  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2082  int HPos, VPos;
2083  if(TextHandler->FindText(3, SName, HPos, VPos))
2084  {
2085  if(TextHandler->TextErase(7, HPos, VPos, SName))
2086  {
2087  ;
2088  } // condition not used
2089 
2090  }
2091  }
2092  }
2093  }
2094  }
2095  if(TrackEraseSuccessfulFlag)
2096  {
2097  CalcHLocMinEtc(2);
2098  SetTrackFinished(false);
2099  }
2100  if(InternalChecks)
2101  {
2102  CheckMapAndTrack(1); // test
2103  CheckMapAndInactiveTrack(1); // test
2104  CheckLocationNameMultiMap(6); // test
2105  }
2106  Utilities->CallLogPop(428);
2107 }
2108 
2109 // ---------------------------------------------------------------------------
2110 
2111 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
2112 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2113 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2114 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2115 {
2116  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2117  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2118  bool PlatAllowedFlag = false;
2119 
2120  TrackLinkingRequiredFlag = false;
2121 /*
2122  Not erase, that covered separately.
2123  First check if Current SpeedButton assigned, then check if a platform and only
2124  permit if an appropriate trackpiece already there & not a same platform there.
2125  - can't enter a platform without track first.
2126  Then for non-platforms, check if a track piece already present at location &
2127  reject if so.
2128 */
2129 
2130  TLocationNameMultiMapEntry LocationNameEntry;
2131 
2132  LocationNameEntry.first = "";
2133  if(CurrentTag == 0)
2134  {
2135  Utilities->CallLogPop(429);
2136  return; // not assigned yet
2137  }
2138  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2139 
2140  TempTrackElement.HLoc = HLocInput;
2141  TempTrackElement.VLoc = VLocInput;
2142  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2143 // new at version 0.6 - set signal aspect depending on build mode
2144 
2145  if(TempTrackElement.TrackType == SignalPost)
2146  {
2147  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2148  // pasting a SignalPost can only have values 1 to 4
2149  {
2151  {
2152  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2153  }
2155  {
2156  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2157  }
2159  {
2160  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2161  }
2162  else
2163  {
2164  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2165  }
2166  }
2167  else if(Aspect == 1)
2168  {
2169  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2170  }
2171  else if(Aspect == 2)
2172  {
2173  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2174  }
2175  else if(Aspect == 3)
2176  {
2177  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2178  }
2179  else
2180  {
2181  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2182  }
2183  }
2184  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2185  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2186  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2187  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2188 
2189  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2190  {
2192  {
2193  NonStationOrLevelCrossingPresent = true;
2194  }
2195  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2196  {
2197  NonStationOrLevelCrossingPresent = true;
2198  }
2199  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2200  {
2201  PlatformPresent = true;
2202  }
2203  // no need to check IMPair.second since if that exists it is because .first is a platform
2204  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2205  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2206  }
2207 // check platforms
2208  if(TempTrackElement.TrackType == Platform)
2209  {
2210  if(FoundFlag) // active track element already there
2211  {
2212  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2213  {
2214  ;
2215  }
2216  // same platform type already there so above keeps PlatAllowedFlag false
2217  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2218  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2219  {
2220  PlatAllowedFlag = true;
2221  }
2222  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2223  {
2224  PlatAllowedFlag = true;
2225  }
2226  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2227  {
2228  PlatAllowedFlag = true;
2229  }
2230  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2231  {
2232  PlatAllowedFlag = true;
2233  }
2234  if(PlatAllowedFlag)
2235  {
2236  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2237  TrackPush(1, TempTrackElement);
2238  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2239  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2240  // Must be called AFTER TrackPush
2241  // No need to plot the element - Clearand ... called after this function called
2242  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2243  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2244 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2245 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2246 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2247  if(InternalChecks)
2248  {
2249  CheckMapAndInactiveTrack(5); // test
2250  CheckLocationNameMultiMap(4); // test
2251  }
2252  Utilities->CallLogPop(430);
2253  return;
2254  }
2255  } // if(FoundFlag)
2256 
2257  Utilities->CallLogPop(431);
2258  return;
2259  } // if platform
2260 
2261 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2262  if(TempTrackElement.TrackType == NamedNonStationLocation)
2263  {
2264  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2265  (!FoundFlag && !InactiveFoundFlag))
2266  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2267  {
2268  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2269  TrackPush(2, TempTrackElement);
2270  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2271  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2272  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2273  {
2274 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2275 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2276 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2277  }
2278  if(InternalChecks)
2279  {
2280  CheckMapAndInactiveTrack(11); // test
2281  CheckLocationNameMultiMap(12); // test
2282  }
2283  Utilities->CallLogPop(432);
2284  return;
2285  }
2286  else
2287  {
2288  Utilities->CallLogPop(433);
2289  return;
2290  }
2291  }
2292 // check if a level crossing - OK if placed on a plain straight track
2293  if(TempTrackElement.TrackType == LevelCrossing)
2294  {
2295  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2296  {
2297  TrackPush(11, TempTrackElement);
2298  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2299 // no need for reference to LC element as can't be open
2300  TrackLinkingRequiredFlag = true;
2301  Utilities->CallLogPop(1907);
2302  return;
2303  }
2304  else
2305  {
2306  Utilities->CallLogPop(1906);
2307  return; // was a level crossing but can't place it for some reason
2308  }
2309  }
2310 
2311 // check if another element already there
2312  else if(FoundFlag || InactiveFoundFlag)
2313  {
2314  Utilities->CallLogPop(434);
2315  return; // something already there (active or inactive track)
2316  }
2317 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2318 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2319 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2320 // do this after pushed into vector so that can use EnterLocationName
2321 
2322  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2323  {
2324  TrackPush(3, TempTrackElement);
2325  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2326  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2327  }
2328  else if(TempTrackElement.TrackType == Points)
2329  {
2330  TrackPush(4, TempTrackElement);
2331  bool BothPointFillets = true;
2332  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2333  }
2334  else if(TempTrackElement.TrackType == SignalPost)
2335  {
2336  TrackPush(10, TempTrackElement);
2337  PlotSignal(12, TempTrackElement, Display);
2338  }
2339  else
2340  {
2341  TrackPush(5, TempTrackElement);
2342  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2343  }
2344  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2345  {
2346  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2347  }
2348  if(InternalChecks)
2349  {
2350  CheckMapAndTrack(2); // test
2351  CheckMapAndInactiveTrack(2); // test
2352  CheckLocationNameMultiMap(5); // test
2353  }
2354  Utilities->CallLogPop(2062);
2355 }
2356 
2357 // ---------------------------------------------------------------------------
2358 
2359 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2360  bool InternalChecks)
2361 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2362 {
2363  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2364  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2365  bool PlatAllowedFlag = false;
2366 
2367  TrackLinkingRequiredFlag = false;
2368  TLocationNameMultiMapEntry LocationNameEntry;
2369 
2370  LocationNameEntry.first = "";
2371  if(TempTrackElement.SpeedTag == 0)
2372  {
2373  Utilities->CallLogPop(2063);
2374  return; // not assigned yet
2375  }
2376  TempTrackElement.HLoc = HLocInput;
2377  TempTrackElement.VLoc = VLocInput;
2378  for(int x = 0; x < 4; x++) // unset any gaps
2379  {
2380  if(TempTrackElement.Config[x] == Gap)
2381  {
2382  TempTrackElement.ConnLinkPos[x] = -1;
2383  }
2384  TempTrackElement.Conn[x] = -1;
2385  }
2386  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2387 // new at version 0.6 - set signal aspect depending on build mode
2388  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2389  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2390 
2391  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2392  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2393  // for the active track element because these aren't set
2394  // if don't do this then get a mismatch error during map checks later
2395 
2396  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2397 
2398  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2399  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2400 
2401  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2402  {
2403  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2404  {
2405  NonStationOrLevelCrossingPresent = true;
2406  }
2407  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2408  {
2409  NonStationOrLevelCrossingPresent = true;
2410  }
2411  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2412  {
2413  PlatformPresent = true;
2414  }
2415  // no need to check IMPair.second since if that exists it is because .first is a platform
2416  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2417  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2418  }
2419 // check platforms
2420  if(TempTrackElement.TrackType == Platform)
2421  {
2422  if(FoundFlag) // active track element already there
2423  {
2424  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2425  {
2426  ;
2427  }
2428  // same platform type already there so above keeps PlatAllowedFlag false
2429  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2430  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2431  {
2432  PlatAllowedFlag = true;
2433  }
2434  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2435  {
2436  PlatAllowedFlag = true;
2437  }
2438  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2439  {
2440  PlatAllowedFlag = true;
2441  }
2442  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2443  {
2444  PlatAllowedFlag = true;
2445  }
2446  if(PlatAllowedFlag)
2447  {
2448  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2449  TrackPush(12, TempTrackElement);
2450 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2451  {
2452  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2453  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2454  }
2455  // Must be called AFTER TrackPush
2456 // No need to plot the element - Clearand ... called after this function called
2457  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2458  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2459 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2460 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2461 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2462  if(InternalChecks)
2463  {
2464  CheckMapAndInactiveTrack(12); // test
2465  CheckLocationNameMultiMap(20); // test
2466  }
2467  Utilities->CallLogPop(2064);
2468  return;
2469  }
2470  } // if(FoundFlag)
2471 
2472  Utilities->CallLogPop(2065);
2473  return;
2474  } // if platform
2475 
2476 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2477  if(TempTrackElement.TrackType == NamedNonStationLocation)
2478  {
2479  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2480  (!FoundFlag && !InactiveFoundFlag))
2481  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2482  {
2483  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2484  TrackPush(13, TempTrackElement);
2485 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2486  {
2487  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2488  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2489  }
2490  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2491  {
2492 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2493 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2494 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2495  }
2496  if(InternalChecks)
2497  {
2498  CheckMapAndInactiveTrack(13); // test
2499  CheckLocationNameMultiMap(21); // test
2500  }
2501  Utilities->CallLogPop(2066);
2502  return;
2503  }
2504  else
2505  {
2506  Utilities->CallLogPop(2067);
2507  return;
2508  }
2509  }
2510 // check if a level crossing - OK if placed on a plain straight track
2511  if(TempTrackElement.TrackType == LevelCrossing)
2512  {
2513  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2514  {
2515  TrackPush(14, TempTrackElement);
2516  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2517 // no need for reference to LC element as can't be open
2518  TrackLinkingRequiredFlag = true;
2519  Utilities->CallLogPop(2068);
2520  return;
2521  }
2522  else
2523  {
2524  Utilities->CallLogPop(2069);
2525  return; // was a level crossing but can't place it for some reason
2526  }
2527  }
2528 
2529 // check if another element already there
2530  else if(FoundFlag || InactiveFoundFlag)
2531  {
2532  Utilities->CallLogPop(2070);
2533  return; // something already there (active or inactive track)
2534  }
2535 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2536 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2537 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2538 // do this after pushed into vector so that can use EnterLocationName
2539 
2540  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2541  {
2542  TrackPush(15, TempTrackElement);
2543  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2544  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2545  }
2546  else if(TempTrackElement.TrackType == Points)
2547  {
2548  TrackPush(16, TempTrackElement);
2549  bool BothPointFillets = true;
2550  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2551  }
2552  else if(TempTrackElement.TrackType == SignalPost)
2553  {
2554  TrackPush(17, TempTrackElement);
2555  PlotSignal(14, TempTrackElement, Display);
2556  }
2557  else
2558  {
2559  TrackPush(18, TempTrackElement);
2560  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2561  }
2562  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2563  {
2564  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2565  }
2566  if(InternalChecks)
2567  {
2568  CheckMapAndTrack(12); // test
2569  CheckMapAndInactiveTrack(14); // test
2570  CheckLocationNameMultiMap(22); // test
2571  }
2572  Utilities->CallLogPop(2071);
2573 }
2574 
2575 // ---------------------------------------------------------------------------
2576 
2577 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2578 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2579 // return bool = true for success
2580 // LocError = true for location error & HLoc & VLoc to be inverted
2581 {
2582  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2583  LocError = false;
2584  SetTrackFinished(false);
2585  if(TrackVector.size() == 0)
2586  {
2587  Utilities->CallLogPop(437);
2588  return(false);
2589  }
2590  if(GapsUnset(7))
2591  {
2592  if(GiveMessages)
2593  {
2594  ShowMessage("Gaps must be set before track can be validated");
2595  }
2596  Utilities->CallLogPop(1135);
2597  return(false);
2598  }
2599 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2600 // returns true for any unset gaps
2602  {
2603  // can keep this exception as protected by the GapsUnset call above
2604  throw Exception("Error, gaps unset when TryToConnectTrack called");
2605  }
2607  CheckGapMap(1); // test
2608 // Gap connections now securely defined
2609 
2610  CheckMapAndTrack(8); // test
2611 
2612 // Perform a pre-check prior to TrackMap being compiled
2613  if(GiveMessages)
2614  {
2615  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2616  {
2617  Utilities->CallLogPop(439);
2618  return(false);
2619  }
2620  }
2621  else
2622  {
2623  if(!LinkTrackNoMessages(1, false))
2624  {
2625  Utilities->CallLogPop(1131);
2626  return(false);
2627  }
2628  }
2629 // here if pre-check successful
2630  if(!RepositionAndMapTrack(0))
2631  {
2632  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2633  Utilities->CallLogPop(1138);
2634  return(false);
2635  }
2636 // now perform the final assembly - FinalCall = true
2637  if(GiveMessages)
2638  {
2639  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2640  {
2641  Utilities->CallLogPop(1116);
2642  return(false);
2643  }
2644  }
2645  else
2646  {
2647  if(!LinkTrackNoMessages(2, true))
2648  {
2649  Utilities->CallLogPop(1132);
2650  return(false);
2651  }
2652  }
2653 // success
2654 
2655  PopulateLCVector(0);
2656  CheckGapMap(2); // test
2657  CheckMapAndTrack(3); // test
2658  CheckMapAndInactiveTrack(3); // test
2659  CheckLocationNameMultiMap(9); // test
2660  SetTrackFinished(true);
2661 
2662 // Build ContinuationNameMap
2663  std::pair<AnsiString, char>TempMapPair;
2664 
2665  ContinuationNameMap.clear();
2666  for(int x = 0; x < Track->TrackVectorSize(); x++)
2667  {
2668  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2669  {
2670  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2671  TempMapPair.second = 'x'; // unused
2672  ContinuationNameMap.insert(TempMapPair);
2673  }
2674  }
2675 
2676 //check (provided TrackFinished is true) if any named (red) locations are without platforms, ie concourses only or concourses and foot crossings
2677 //(don't report blue areas without track as these unlikely to be mistakes)
2678 
2679  if(TrackFinished)
2680  {
2681  AnsiString Name = "";
2682  typedef std::list<AnsiString> TNoPlatsList;
2683  TNoPlatsList::iterator NPLIt;
2684  TNoPlatsList NoPlatsList;
2685  typedef std::list<AnsiString> TLocNameList;
2686  TLocNameList LocNameList; //single entry for each name
2689  for(TLocationNameMultiMapIterator LNMMIt = LocationNameMultiMap.begin(); LNMMIt != LocationNameMultiMap.end(); LNMMIt++)
2690  {
2691  LocNameList.push_back(LNMMIt->first);
2692  }
2693  LocNameList.sort();
2694  LocNameList.unique();
2695  for(TLocNameList::iterator LNLIt = LocNameList.begin(); LNLIt != LocNameList.end(); LNLIt++)
2696  {
2697  Name = *LNLIt;
2698  MMRange = LocationNameMultiMap.equal_range(Name);
2699  if(MMRange.first == MMRange.second) //can't find it - should always do but include as a safeguard
2700  {
2701  continue;
2702  }
2703  for(TLocationNameMultiMapIterator LNMMIt = MMRange.first; LNMMIt != MMRange.second; LNMMIt++)
2704  {
2705  if((LNMMIt->second) < 0) //active track element
2706  {
2707  if(TrackElementAt(1401, -1 - LNMMIt->second).TrackType != FootCrossing)
2708  {
2709  break;
2710  }
2711  }
2712  else //inactive
2713  {
2714  if(InactiveTrackElementAt(1402, LNMMIt->second).TrackType != Concourse)
2715  {
2716  break;
2717  }
2718  }
2719  TempIt = MMRange.second;
2720  if(LNMMIt == --TempIt) //reached last named element & all concourses or foot crossings
2721  {
2722  NoPlatsList.push_back(Name);
2723  }
2724  }
2725  }
2726  if(!NoPlatsList.empty())
2727  {
2728  AnsiString NoPlatsAnsiList = "";
2729  for(NPLIt = NoPlatsList.begin(); NPLIt != NoPlatsList.end(); NPLIt++)
2730  {
2731  NoPlatsAnsiList += *NPLIt + '\n';
2732  }
2733  if(!NoPlatsMessageSent)
2734  {
2735  if(NoPlatsList.size() > 1)
2736  {
2737  ShowMessage("Please note: the following locations have no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2738  }
2739  else
2740  {
2741  ShowMessage("Please note: the following location has no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2742  }
2743  NoPlatsMessageSent = true;
2744  }
2745  }
2746  }
2747  Utilities->CallLogPop(440);
2748  return(true);
2749 }
2750 
2751 // ---------------------------------------------------------------------------
2752 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2753 // unused - too time-consuming - double brute force search
2754 {
2755  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2756  int NewHLoc, NewVLoc;
2757  bool ConnectionFoundFlag, LinkFoundFlag;
2758 
2759  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2760  {
2761  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2762  {
2763  if(TrackElementAt(1061, x).Link[y] <= 0)
2764  {
2765  continue; // no link
2766  }
2767  if(TrackElementAt(1062, x).Config[y] == End)
2768  {
2769  continue; // buffer or continuation
2770  }
2771  if(TrackElementAt(1063, x).Config[y] == Gap)
2772  {
2773  continue; // gap jump
2774  }
2775  // get required H & V for track element joining link 'y'
2776  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2777  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2778  // find track element if present
2779  ConnectionFoundFlag = false;
2780  for(unsigned int z = 0; z < TrackVector.size(); z++)
2781  {
2782 // if(TrackElementAt(5, z).TrackType == Platform)
2783 // continue; //skip platforms
2784  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2785  {
2786  ConnectionFoundFlag = true;
2787  // find connecting link in the newly found track element if there is one
2788  LinkFoundFlag = false;
2789  for(unsigned int a = 0; a < 4; a++)
2790  {
2791  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2792  {
2793  LinkFoundFlag = true;
2794  }
2795  }
2796  // if there isn't a corresponding link set the invert values for the offending element
2797  if(!LinkFoundFlag)
2798  {
2799  HLoc = TrackElementAt(1072, x).HLoc;
2800  VLoc = TrackElementAt(1073, x).VLoc;
2801  Utilities->CallLogPop(441);
2802  return(true);
2803  }
2804  break; // success, so break out of 'z' loop
2805  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2806 
2807  } // for z...
2808  // if there isn't a connection set the invert values for the offending element
2809  if(!ConnectionFoundFlag)
2810  {
2811  HLoc = TrackElementAt(1074, x).HLoc;
2812  VLoc = TrackElementAt(1075, x).VLoc;
2813  Utilities->CallLogPop(442);
2814  return(true);
2815  }
2816  } // for y....
2817  } // for x...
2818  Utilities->CallLogPop(443);
2819  return(false); // all OK
2820 }
2821 
2822 // ---------------------------------------------------------------------------
2823 
2824 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2825 {
2826  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2827  TrackElement.LogTrack(0));
2828  bool FoundFlag;
2829 
2830  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2831  if(FoundFlag)
2832  {
2833  TrackElement = TrackElementAt(1076, Position);
2834  }
2835  Utilities->CallLogPop(444);
2836  return(FoundFlag);
2837 }
2838 
2839 // ---------------------------------------------------------------------------
2840 
2842 {
2843  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2844  if(NextTrackElementPtr >= TrackVector.end())
2845  {
2846  Utilities->CallLogPop(1336);
2847  return(false);
2848  }
2849  Next = *NextTrackElementPtr;
2851  Utilities->CallLogPop(1337);
2852  return(true);
2853 }
2854 
2855 // ---------------------------------------------------------------------------
2856 
2858 {
2859  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2861  {
2862  Utilities->CallLogPop(1338);
2863  return(false);
2864  }
2865  Next = *NextTrackElementPtr;
2867  Utilities->CallLogPop(1339);
2868  return(true);
2869 }
2870 
2871 // ---------------------------------------------------------------------------
2872 
2873 int TTrack::NumberOfGaps(int Caller)
2874 
2875 {
2876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2877  int Count = 0;
2878 
2879  if(TrackVector.size() == 0)
2880  {
2881  Utilities->CallLogPop(1340);
2882  return(0);
2883  }
2884  for(unsigned int x = 0; x < TrackVector.size(); x++)
2885  {
2886  if(TrackElementAt(1077, x).TrackType == GapJump)
2887  {
2888  Count++;
2889  }
2890  }
2891  Utilities->CallLogPop(1341);
2892  return(Count);
2893 }
2894 
2895 // ---------------------------------------------------------------------------
2897 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2898 // returns true for any unset gaps
2899 {
2900  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2901  bool UnsetGaps = false;
2902 
2903  if(TrackVector.size() == 0)
2904  {
2905  Utilities->CallLogPop(445);
2906  return(false);
2907  }
2908  for(unsigned int x = 0; x < TrackVector.size(); x++)
2909  {
2910  if(TrackElementAt(1078, x).TrackType != GapJump)
2911  {
2912  for(unsigned int y = 0; y < 4; y++)
2913  {
2914  TrackElementAt(1079, x).Conn[y] = -1;
2915  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
2916  }
2917  }
2918  else // GapJump
2919  {
2920 // int tempint = TrackElementAt(, x).Conn[0);
2921 
2922  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
2923  {
2924  for(unsigned int y = 0; y < 4; y++)
2925  {
2926  TrackElementAt(1082, x).Conn[y] = -1;
2927  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
2928  }
2929  UnsetGaps = true;
2930  continue; // to next 'x'
2931  }
2932  else // set, but may not have matching element, or that element may not be set
2933  {
2934  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2935  {
2936  TrackElementAt(1084, x).Conn[y] = -1;
2937  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
2938  }
2939 
2940  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
2941  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2942  {
2943  for(unsigned int y = 0; y < 4; y++)
2944  {
2945  TrackElementAt(1087, x).Conn[y] = -1;
2946  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
2947  }
2948  UnsetGaps = true;
2949  continue; // to next 'x'
2950  }
2951 // here if gap connection is itself a GapJump
2952  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
2953  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
2954  // if not clear Conns & CLks & reset Lk[0]
2955  {
2956  for(unsigned int y = 0; y < 4; y++)
2957  {
2958  TrackElementAt(1090, x).Conn[y] = -1;
2959  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
2960  }
2961  UnsetGaps = true;
2962  continue; // to next 'x'
2963  }
2964 // here if gap connection itself points back to 'x' so these two GapJumps match properly
2965 // hence no more action needed on these Conns & CLks
2966  }
2967  } // else //gap jump
2968 
2969  } // for x...
2970  Utilities->CallLogPop(446);
2971  return(UnsetGaps);
2972 }
2973 
2974 // ---------------------------------------------------------------------------
2975 
2976 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
2977 {
2978 // VecFile already open and its pointer at right place on calling
2979  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
2980  int TempInt;
2981 
2982  TrackClear(1);
2983 // load track elements
2984  int NumberOfActiveElements = 0;
2985 
2986  GraphicsFollow = false;
2987  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2988  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
2989 
2990  if(MarkerString[MarkerString.Length()] == '1')
2991  {
2992  GraphicsFollow = true;
2993  }
2994  for(int x = 0; x < NumberOfActiveElements; x++)
2995  {
2996  VecFile >> TempInt; // TrackVectorNumber, not used
2997  VecFile >> TempInt; // SpeedTag
2998  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2999  VecFile >> TempInt;
3000  TrackElement.HLoc = TempInt;
3001  VecFile >> TempInt;
3002  TrackElement.VLoc = TempInt;
3003  if(TrackElement.TrackType == GapJump)
3004  {
3005  VecFile >> TempInt;
3006  TrackElement.ConnLinkPos[0] = TempInt;
3007  VecFile >> TempInt;
3008  TrackElement.Conn[0] = TempInt;
3009  }
3010  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3011  {
3012  VecFile >> TempInt;
3013  TrackElement.Attribute = TempInt;
3014  }
3015  if(TrackElement.TrackType == SignalPost)
3016  {
3017  VecFile >> TempInt;
3018  if(TempInt == 0)
3019  {
3020  TrackElement.CallingOnSet = false;
3021  }
3022  else
3023  {
3024  TrackElement.CallingOnSet = true;
3025  }
3026  }
3027  VecFile >> TempInt;
3028  TrackElement.Length01 = TempInt;
3029  VecFile >> TempInt;
3030  TrackElement.Length23 = TempInt;
3031  VecFile >> TempInt;
3032  if((TempInt != -1) && (TempInt < 10))
3033  {
3034  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3035  }
3036  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3037  {
3038  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3039  }
3040  TrackElement.SpeedLimit01 = TempInt;
3041  VecFile >> TempInt;
3042  if((TempInt != -1) && (TempInt < 10))
3043  {
3044  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3045  }
3046  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3047  {
3048  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3049  }
3050  TrackElement.SpeedLimit23 = TempInt;
3051 
3052  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3053  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
3054  SetElementID(0, TrackElement);
3055  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
3056 // new for v0.6
3057  if(TrackElement.TrackType == SignalPost)
3058  {
3059  if(Marker[1] == '3')
3060  {
3061  TrackElement.SigAspect = TTrackElement::ThreeAspect;
3062  }
3063  else if(Marker[1] == '2')
3064  {
3065  TrackElement.SigAspect = TTrackElement::TwoAspect;
3066  }
3067  else if(Marker[1] == 'G')
3068  {
3069  TrackElement.SigAspect = TTrackElement::GroundSignal;
3070  }
3071  else
3072  {
3073  TrackElement.SigAspect = TTrackElement::FourAspect;
3074  }
3075  }
3076  if(TrackElement.SpeedTag != 0)
3077  {
3078  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
3079  }
3080  }
3081  int NumberOfInactiveElements = 0;
3082 
3083  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3084  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
3085  for(int x = 0; x < NumberOfInactiveElements; x++)
3086  {
3087  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
3088  VecFile >> TempInt; // SpeedTag
3089  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3090  VecFile >> TempInt;
3091  TrackElement.HLoc = TempInt;
3092  VecFile >> TempInt;
3093  TrackElement.VLoc = TempInt;
3094  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3095  SetElementID(3, TrackElement);
3096  TrackPush(9, TrackElement);
3097  Utilities->LoadFileString(VecFile); // marker
3098  }
3099  bool LocError = false; // needed for TryToConnectTrack but not used
3100  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3101 
3102  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3103  {
3104  SetTrackFinished(true);
3105  }
3106  else
3107  {
3108  SetTrackFinished(false);
3109  }
3110 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3111 // CheckMapAndInactiveTrack(8);
3112 // CheckLocationNameMultiMap(10);
3113  Utilities->CallLogPop(448);
3114 }
3115 
3116 // ---------------------------------------------------------------------------
3117 
3118 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3119 {
3120 // VecFile already open and its pointer at right place on calling
3121  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3122 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3123 // & load into UserGraphicItem then store in UserGraphicVector
3124  UserGraphicVector.clear();
3125  TUserGraphicItem UGI;
3126  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3127 
3128  for(int x = 0; x < NumberOfGraphics; x++)
3129  {
3130  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3131  UGI.HPos = Utilities->LoadFileInt(VecFile);
3132  UGI.VPos = Utilities->LoadFileInt(VecFile);
3133  UGI.Width = 0; // provisional value
3134  UGI.Height = 0; // provisional value
3135  UGI.UserGraphic = NULL; // provisional value
3136  UserGraphicVector.push_back(UGI);
3137  }
3138 // now load the map & set Width, Height & TPicture*
3139  bool FileError = false;
3140 
3141  for(int x = 0; x < NumberOfGraphics; x++)
3142  {
3143  if(FileError)
3144  {
3145  break; // otherwise keeps going round the loop
3146  }
3147  UGI = UserGraphicVectorAt(0, x);
3148  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3149  {
3150  try
3151  {
3152 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3153  UGME.first = UGI.FileName;
3154  UGME.second = new TPicture;
3155  UGME.second->LoadFromFile(UGME.first); // errors caught below
3156  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3157  {
3158  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3159  }
3160  UGI.UserGraphic = UGME.second;
3161  UGI.Width = UGI.UserGraphic->Width;
3162  UGI.Height = UGI.UserGraphic->Height;
3163  UserGraphicVectorAt(1, x) = UGI;
3164  }
3165  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3166  {
3167  //message already sent in CheckUserGraphics
3168  FileError = true;
3169  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3170  if(!UserGraphicMap.empty())
3171  {
3172  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3173  {
3174  delete UGMIt->second;
3175  }
3176  UserGraphicMap.clear();
3177  }
3178  }
3179  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3180  {
3181  //message already sent in CheckUserGraphics
3182  FileError = true;
3183  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3184  if(!UserGraphicMap.empty())
3185  {
3186  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3187  {
3188  delete UGMIt->second;
3189  }
3190  UserGraphicMap.clear();
3191  }
3192  }
3193  }
3194  else
3195  {
3196  bool FoundInMap = false;
3197  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3198  {
3199  if(UGI.FileName == UGMIt->first) // already exists in map
3200  {
3201  UGI.UserGraphic = UGMIt->second;
3202  UGI.Width = UGI.UserGraphic->Width;
3203  UGI.Height = UGI.UserGraphic->Height;
3204  UserGraphicVectorAt(2, x) = UGI;
3205  FoundInMap = true;
3206  break;
3207  }
3208  }
3209  if(!FoundInMap)
3210  {
3211  try
3212  {
3214  UGME.first = UGI.FileName;
3215  UGME.second = new TPicture;
3216  UGME.second->LoadFromFile(UGME.first); // errors caught below
3217  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3218  {
3219  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3220  }
3221  UGI.UserGraphic = UGME.second;
3222  UGI.Width = UGI.UserGraphic->Width;
3223  UGI.Height = UGI.UserGraphic->Height;
3224  UserGraphicVectorAt(3, x) = UGI;
3225  }
3226  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3227  {
3228  //message already sent in CheckUserGraphics
3229  FileError = true;
3230  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3231  if(!UserGraphicMap.empty())
3232  {
3233  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3234  {
3235  delete UGMIt->second;
3236  }
3237  UserGraphicMap.clear();
3238  }
3239  }
3240  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3241  {
3242  //message already sent in CheckUserGraphics
3243  FileError = true;
3244  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3245  if(!UserGraphicMap.empty())
3246  {
3247  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3248  {
3249  delete UGMIt->second;
3250  }
3251  UserGraphicMap.clear();
3252  }
3253  }
3254  }
3255  }
3256  }
3257  Utilities->CallLogPop(2167);
3258 }
3259 
3260 // ---------------------------------------------------------------------------
3261 
3262 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3263 {
3264 // VecFile already open and its pointer at right place on calling
3265 // if GraphicsFollow true, then save Marker as **Active elements**1
3266 // save trackfinished flag
3267  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3268  TTrackElement TrackElement, InactiveTrackElement;
3269 
3270 // save track elements
3271  Utilities->SaveFileInt(VecFile, TrackVector.size());
3272  if(GraphicsFollow)
3273  {
3274  VecFile << "**Active elements**1" << '\0' << '\n';
3275  }
3276  else
3277  {
3278  VecFile << "**Active elements**" << '\0' << '\n';
3279  }
3280  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3281  {
3282  TrackElement = TrackElementAt(1092, x);
3283  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3284  VecFile << TrackElement.SpeedTag << '\n';
3285  VecFile << TrackElement.HLoc << '\n';
3286  VecFile << TrackElement.VLoc << '\n';
3287  if(TrackElement.TrackType == GapJump)
3288  {
3289  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3290  VecFile << TrackElement.Conn[0] << '\n';
3291  }
3292  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3293  {
3294  VecFile << TrackElement.Attribute << '\n';
3295  }
3296  if(TrackElement.TrackType == SignalPost)
3297  {
3298  if(TrackElement.CallingOnSet)
3299  {
3300  VecFile << int(1) << '\n';
3301  }
3302  else
3303  {
3304  VecFile << int(0) << '\n';
3305  }
3306  }
3307  VecFile << TrackElement.Length01 << '\n';
3308  VecFile << TrackElement.Length23 << '\n';
3309  VecFile << TrackElement.SpeedLimit01 << '\n';
3310  VecFile << TrackElement.SpeedLimit23 << '\n';
3311  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3312  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3313 // new for v0.6
3314  if(TrackElement.TrackType == SignalPost)
3315  {
3316  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3317  {
3318  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3319  }
3320  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3321  {
3322  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3323  }
3324  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3325  {
3326  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3327  }
3328  else // 4 aspect
3329  {
3330  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3331  }
3332  }
3333  else
3334  {
3335  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3336  }
3337  }
3338 
3339  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3340  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3341  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3342  {
3343  InactiveTrackElement = InactiveTrackElementAt(136, x);
3344  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3345  VecFile << InactiveTrackElement.SpeedTag << '\n';
3346  VecFile << InactiveTrackElement.HLoc << '\n';
3347  VecFile << InactiveTrackElement.VLoc << '\n';
3348  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3349  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3350  }
3351  Utilities->CallLogPop(449);
3352 }
3353 
3354 // ---------------------------------------------------------------------------
3355 
3356 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3357 {
3358 // VecFile already open and its pointer at right place on calling
3359 // check trackfinished flag
3360 // inactive elements follow immediately after active elements, no need to check for a marker between them
3361  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3362  int TempInt;
3363 
3364  GraphicsFollow = false;
3365  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3366  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3367  {
3368  Utilities->CallLogPop(1513);
3369  return(false);
3370  }
3371 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3372  AnsiString MarkerString;
3373 
3374  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3375  {
3376  Utilities->CallLogPop(1758);
3377  return(false);
3378  }
3379  if(MarkerString[MarkerString.Length()] == '1')
3380  {
3381  GraphicsFollow = true;
3382  }
3383  for(int x = 0; x < NumberOfActiveElements; x++)
3384  {
3385  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3386  {
3387  Utilities->CallLogPop(1759);
3388  return(false);
3389  }
3390  VecFile >> TempInt;
3391  int SpeedTag = TempInt;
3392  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3393  {
3394  Utilities->CallLogPop(1514);
3395  return(false);
3396  }
3397  VecFile >> TempInt;
3398  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3399  {
3400  Utilities->CallLogPop(1495);
3401  return(false);
3402  }
3403  VecFile >> TempInt;
3404  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3405  {
3406  Utilities->CallLogPop(1497);
3407  return(false);
3408  }
3409  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3410  {
3411  VecFile >> TempInt;
3412  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3413  {
3414  Utilities->CallLogPop(1499);
3415  return(false);
3416  }
3417  VecFile >> TempInt;
3418  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3419  {
3420  Utilities->CallLogPop(1500);
3421  return(false);
3422  }
3423  }
3424  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3425  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3426  {
3427  VecFile >> TempInt;
3428  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3429  {
3430  Utilities->CallLogPop(1502);
3431  return(false);
3432  }
3433  }
3434  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3435  {
3436  VecFile >> TempInt;
3437  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3438  {
3439  Utilities->CallLogPop(1155);
3440  return(false);
3441  }
3442  }
3443  VecFile >> TempInt;
3444  if((TempInt < -1) || (TempInt > 999999)) // Length01
3445  {
3446  Utilities->CallLogPop(1503);
3447  return(false);
3448  }
3449  VecFile >> TempInt;
3450  if((TempInt < -1) || (TempInt > 999999)) // Length23
3451  {
3452  Utilities->CallLogPop(1504);
3453  return(false);
3454  }
3455  VecFile >> TempInt;
3456  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3457  {
3458  Utilities->CallLogPop(1505);
3459  return(false);
3460  }
3461  VecFile >> TempInt;
3462  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3463  {
3464  Utilities->CallLogPop(1506);
3465  return(false);
3466  }
3467  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3468  {
3469  Utilities->CallLogPop(1142);
3470  return(false); // LocationName
3471  }
3472  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3473  {
3474  Utilities->CallLogPop(1143);
3475  return(false); // ActiveTrackElementName
3476  }
3477  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3478  {
3479  Utilities->CallLogPop(1787);
3480  return(false); // marker
3481  }
3482  }
3483  int NumberOfInactiveElements = 0;
3484 
3485  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3486  if(NumberOfInactiveElements < 0) // No of active elements
3487  {
3488  Utilities->CallLogPop(1493);
3489  return(false);
3490  }
3491  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3492  {
3493  Utilities->CallLogPop(1764);
3494  return(false); // **Inactive elements** marker
3495  }
3496  for(int x = 0; x < NumberOfInactiveElements; x++)
3497  {
3498  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3499  {
3500  Utilities->CallLogPop(1765);
3501  return(false);
3502  }
3503  VecFile >> TempInt;
3504  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3505  {
3506  Utilities->CallLogPop(1494);
3507  return(false);
3508  }
3509  VecFile >> TempInt;
3510  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3511  {
3512  Utilities->CallLogPop(1496);
3513  return(false);
3514  }
3515  VecFile >> TempInt;
3516  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3517  {
3518  Utilities->CallLogPop(1498);
3519  return(false);
3520  }
3521  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3522  {
3523  Utilities->CallLogPop(1144);
3524  return(false); // LocationName
3525  }
3526  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3527  {
3528  Utilities->CallLogPop(1788);
3529  return(false); // marker
3530  }
3531  }
3532  Utilities->CallLogPop(1507);
3533  return(true);
3534 }
3535 
3536 // ---------------------------------------------------------------------------
3537 
3538 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3539 {
3540  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3541  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3542 
3543  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3544  {
3545  Utilities->CallLogPop(2168);
3546  return(false);
3547  }
3548  // filename in Graphics folder, then HPos, then VPos
3549  AnsiString FileName = "", TempStr = "";
3550 
3551  for(int x = 0; x < NumberOfGraphics; x++)
3552  {
3553  TPicture *TempPicture = new TPicture;
3554  try
3555  {
3556  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3557  {
3558  Utilities->CallLogPop(2169);
3559  delete TempPicture;
3560  return(false);
3561  }
3562  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3563  delete TempPicture;
3564  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3565  {
3566  Utilities->CallLogPop(2170);
3567  return(false);
3568  }
3569  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3570  {
3571  Utilities->CallLogPop(2171);
3572  return(false);
3573  }
3574  }
3575  catch(const EInvalidGraphic &e) //non error catch
3576  {
3577  //move file pointer to end of graphic section for later checks in session files
3578  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3579  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3580  for(int y = x + 1; y < NumberOfGraphics; y++)
3581  {
3582  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3583  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3584  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3585  }
3586  ShowMessage(FileName +
3587  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3588  Utilities->CallLogPop(2172);
3589  delete TempPicture;
3590  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3591  }
3592  catch(const Exception &e) //non error catch
3593  {
3594  //move file pointer to end of graphic section for later checks in session files
3595  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3596  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3597  for(int y = x + 1; y < NumberOfGraphics; y++)
3598  {
3599  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3600  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3601  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3602  }
3603  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3604  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3605  Utilities->CallLogPop(2173);
3606  delete TempPicture;
3607  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3608  }
3609  }
3610  Utilities->CallLogPop(2174);
3611  return(true);
3612 }
3613 
3614 // ---------------------------------------------------------------------------
3615 
3616 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3617 {
3618  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3619  int VecSize = Track->BarriersDownVector.size();
3620 
3621  Utilities->SaveFileInt(OutFile, VecSize);
3622  for(int x = 0; x < VecSize; x++)
3623  {
3625  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3626  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3627  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3628  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3629  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3630  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3631  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3632  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3633  }
3634  Utilities->CallLogPop(1963);
3635 }
3636 
3637 // ---------------------------------------------------------------------------
3638 
3639 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3640 {
3641  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3642  int VecSize = Track->ChangingLCVector.size();
3643 
3644  Utilities->SaveFileInt(OutFile, VecSize);
3645  for(int x = 0; x < VecSize; x++)
3646  {
3648  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3649  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3650  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3651  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3652  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3653  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3654  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3655  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3656  }
3657  Utilities->CallLogPop(1980);
3658 }
3659 
3660 // ---------------------------------------------------------------------------
3661 
3662 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3663 {
3664  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3665  int VecSize = Utilities->LoadFileInt(VecFile);
3666 
3667  for(int x = 0; x < VecSize; x++)
3668  {
3669  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3670  {
3671  Utilities->CallLogPop(1970);
3672  return(false);
3673  }
3674  if(!Utilities->CheckFileBool(VecFile))
3675  {
3676  Utilities->CallLogPop(1971);
3677  return(false);
3678  }
3679  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3680  {
3681  Utilities->CallLogPop(1972);
3682  return(false);
3683  }
3684  if(!Utilities->CheckFileDouble(VecFile))
3685  {
3686  Utilities->CallLogPop(1973);
3687  return(false);
3688  }
3689  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3690  {
3691  Utilities->CallLogPop(1974);
3692  return(false);
3693  }
3694  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3695  {
3696  Utilities->CallLogPop(1975);
3697  return(false);
3698  }
3699  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3700  {
3701  Utilities->CallLogPop(1976);
3702  return(false);
3703  }
3704  if(!Utilities->CheckFileDouble(VecFile))
3705  {
3706  Utilities->CallLogPop(1977);
3707  return(false);
3708  }
3709  }
3710  Utilities->CallLogPop(1978);
3711  return(true);
3712 }
3713 
3714 // ---------------------------------------------------------------------------
3715 
3716 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3717 {
3718  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3719  int VecSize = Utilities->LoadFileInt(VecFile);
3720 
3721  for(int x = 0; x < VecSize; x++)
3722  {
3723  TActiveLevelCrossing TALC;
3724  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3725  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3726  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3727  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3728  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3729  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3730  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3731  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3732  BarriersDownVector.push_back(TALC);
3733  }
3734  Utilities->CallLogPop(1979);
3735 }
3736 
3737 // ---------------------------------------------------------------------------
3738 
3739 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3740 /*
3741  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3742  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3743  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3744 */
3745 {
3746  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3747  TTrackElement Next;
3748 
3749 // Disp->ClearDisplay();
3751  while(ReturnNextInactiveTrackElement(0, Next))
3752  {
3753  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3754  {
3755  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3756  {
3757  // only plot if on screen, to save time
3758  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3760  {
3761  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3762  }
3763  }
3764  }
3765  }
3766 
3767  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3768 
3769  NextTrackElementPtr = TrackVector.begin();
3770  while(ReturnNextTrackElement(0, Next))
3771  {
3772  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3773  {
3774  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3776  {
3777  if(Next.TrackType == Points)
3778  {
3779  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3780  }
3781  else if(Next.TrackType == SignalPost)
3782  {
3783  PlotSignal(9, Next, Disp);
3784  }
3785  else if(Next.TrackType == GapJump)
3786  {
3787  PlotGap(0, Next, Disp);
3788  }
3789  else if(Next.TrackType == Continuation) //added for multiplayer graphic overlays
3790  {
3791  PlotContinuation(0, Next, Disp);
3792  }
3793  else
3794  {
3795  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3796  }
3797  }
3798  }
3799  }
3800 
3801  if(BothPointFilletsAndBasicLCs)
3802  {
3804  while(ReturnNextInactiveTrackElement(4, Next))
3805  {
3806  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3807  {
3808  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3809  {
3810  // only plot if on screen, to save time, & OK as plotting one by one here
3811  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3813  {
3814  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3815  {
3816  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3817  }
3818  else
3819  {
3820  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3821  }
3822  }
3823  }
3824  }
3825  }
3826  }
3827  Disp->Update();
3828  Utilities->CallLogPop(468);
3829 }
3830 
3831 // ---------------------------------------------------------------------------
3832 
3833 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3834 {
3835  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3836  if(UserGraphicVector.empty())
3837  {
3838  Utilities->CallLogPop(2175);
3839  return;
3840  }
3841  TUserGraphicItem UGI;
3842 
3843  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3844  {
3845  UGI = UserGraphicVectorAt(4, x);
3846  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3847  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3848  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3849  {
3850  Disp->PlotAndAddUserGraphic(0, UGI);
3851  }
3852  }
3853  Disp->Update();
3854  Utilities->CallLogPop(2176);
3855 }
3856 
3857 // ---------------------------------------------------------------------------
3858 
3859 void TTrack::WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap) //added text after inactives at v2.10.0
3860 /*
3861  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3862 */
3863 {
3864  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackAndTextToImage");
3865 // need to change graphics back to black on white if have a dark background
3866  TColor OldTransparentColour = Utilities->clTransparent;
3867 
3869  {
3870  Utilities->clTransparent = TColor(0xFFFFFF); // white
3873  }
3874  TTrackElement Next;
3875 
3876  Bitmap->Canvas->CopyMode = cmSrcCopy;
3878  Graphics::TBitmap *GraphicOutput;
3879 
3880  while(ReturnNextInactiveTrackElement(2, Next))
3881  {
3882  GraphicOutput = Next.GraphicPtr;
3883  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3884  {
3885  if(Next.LocationName == "") // plot as named or unnamed (striped)
3886  {
3887  // default is not striped
3888  switch(Next.SpeedTag)
3889  {
3890  case 76: // t platform
3891  GraphicOutput = RailGraphics->gl76Striped;
3892  break;
3893 
3894  case 77: // h platform
3895  GraphicOutput = RailGraphics->bm77Striped;
3896  break;
3897 
3898  case 78: // v platform
3899  GraphicOutput = RailGraphics->bm78Striped;
3900  break;
3901 
3902  case 79: // r platform
3903  GraphicOutput = RailGraphics->gl79Striped;
3904  break;
3905 
3906  case 96: // concourse
3907  GraphicOutput = RailGraphics->ConcourseStriped;
3908  break;
3909 
3910  case 129: // v footbridge
3911  GraphicOutput = RailGraphics->gl129Striped;
3912  break;
3913 
3914  case 130: // h footbridge
3915  GraphicOutput = RailGraphics->gl130Striped;
3916  break;
3917 
3918  case 131: // non-station named loc
3919  GraphicOutput = RailGraphics->bmNameStriped;
3920  break;
3921 
3922  case 145: // v underpass
3923  GraphicOutput = RailGraphics->gl145Striped;
3924  break;
3925 
3926  case 146: // h underpass
3927  GraphicOutput = RailGraphics->gl146Striped;
3928  break;
3929 
3930  default:
3931  GraphicOutput = Next.GraphicPtr;
3932  break;
3933  }
3934  }
3935  if(Next.SpeedTag == 144) // level crossing
3936  {
3937  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3938  {
3939  GraphicOutput = RailGraphics->LCBothVer;
3940  }
3941  else
3942  {
3943  GraphicOutput = RailGraphics->LCBothHor;
3944  }
3945  }
3946  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3947  }
3948  }
3949 
3950  TextHandler->WriteTextToImage(0, Bitmap); //so overwrites inactive elements //added at v2.10.0
3951 
3952 
3953  NextTrackElementPtr = TrackVector.begin();
3954  while(ReturnNextTrackElement(2, Next))
3955  {
3956  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3957  {
3958  if(Next.TrackType == Points) // plot both fillets
3959  {
3960  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3961  if(Next.SpeedTag < 28)
3962  {
3963  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3965  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3967  }
3968  else if(Next.SpeedTag < 132)
3969  {
3970  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3971  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
3972  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3973  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
3974  }
3975  else
3976  {
3977  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3978  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
3979  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3980  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
3981  }
3982  }
3983  else if(Next.TrackType == GapJump) // plot as connected or unconnected
3984  {
3985  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
3986  {
3987  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3988  }
3989  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
3990  {
3991  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
3992  }
3993  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
3994  {
3995  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3996  }
3997  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
3998  {
3999  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
4000  }
4001  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
4002  {
4003  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4004  }
4005  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
4006  {
4007  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
4008  }
4009  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
4010  {
4011  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4012  }
4013  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
4014  {
4015  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
4016  }
4017  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
4018  {
4019  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4020  }
4021  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
4022  {
4023  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
4024  }
4025  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
4026  {
4027  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4028  }
4029  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
4030  {
4031  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
4032  }
4033  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
4034  {
4035  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4036  }
4037  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
4038  {
4039  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
4040  }
4041  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
4042  {
4043  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4044  }
4045  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
4046  {
4047  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
4048  }
4049  }
4050  // below added for version 0.6, only stop signals to be drawn
4051  else if(Next.TrackType == SignalPost)
4052  {
4053  for(int x = 0; x < 40; x++)
4054  {
4055  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
4056  {
4057  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4058  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4059  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4060  int HOffset = 0;
4061  if(Next.SpeedTag > 73)
4062  {
4063  HOffset = 5;
4064  }
4065  else if(Next.SpeedTag == 71)
4066  {
4067  HOffset = 9;
4068  }
4069  int VOffset = 0;
4070  if(Next.SpeedTag == 69)
4071  {
4072  VOffset = 9;
4073  }
4074  else if(Next.SpeedTag == 72)
4075  {
4076  VOffset = 5;
4077  }
4078  else if(Next.SpeedTag == 74)
4079  {
4080  VOffset = 5;
4081  }
4082  Graphics::TBitmap *GraphicPtr;
4083  if(Next.SpeedTag > 71)
4084  {
4085  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4086  }
4087  else if(Next.SpeedTag < 70)
4088  {
4089  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4090  }
4091  else
4092  {
4093  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4094  }
4095  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4096  // plot special signal platform if present
4097  Graphics::TBitmap* SignalPlatformGraphic;
4098  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4099  {
4100  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4101  }
4102  // now plot signal (double yellow overwrites most of signal platform if present)
4103  // below amended for version 0.6
4105  {
4106  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4107  }
4108  else if(Next.SigAspect == TTrackElement::TwoAspect)
4109  {
4110  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4111  }
4112  else if(Next.SigAspect == TTrackElement::GroundSignal)
4113  {
4114  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4115  }
4116  else // 4 aspect
4117  {
4118  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4119  }
4120  break;
4121  }
4122  }
4123  }
4124  else
4125  {
4126  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4127  }
4128  }
4129  }
4130  if(OldTransparentColour != clB5G5R5)
4131  {
4132  Utilities->clTransparent = OldTransparentColour; // restore
4135  }
4136  Utilities->CallLogPop(1533);
4137 }
4138 
4139 // ---------------------------------------------------------------------------
4140 
4141 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4142 {
4143  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4144  if(UserGraphicVector.empty())
4145  {
4146  Utilities->CallLogPop(2192);
4147  return;
4148  }
4149  else
4150  {
4151  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4152  {
4153  Bitmap->Canvas->CopyMode = cmSrcCopy;
4154  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4155  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4156  }
4157  }
4158  Utilities->CallLogPop(2193);
4159 }
4160 
4161 // ---------------------------------------------------------------------------
4162 
4163 void TTrack::WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
4164 /*
4165  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4166  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4167 */
4168 {
4169  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackAndTextToImage");
4170 // need to change graphics back to black on white if have a dark background
4171  TColor OldTransparentColour = Utilities->clTransparent;
4172 
4174  {
4175  Utilities->clTransparent = TColor(0xFFFFFF); // white
4178  }
4179  TTrackElement Next;
4180 
4181  Bitmap->Canvas->CopyMode = cmSrcCopy;
4183  Graphics::TBitmap *GraphicOutput;
4184 
4185  while(ReturnNextInactiveTrackElement(3, Next))
4186  {
4187  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4188  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4189  {
4190  if(Next.SpeedTag == 144) // level crossing
4191  {
4192  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4193  if(BaseElement == 1) // hor element
4194  {
4195  if(Next.Attribute == 1) // open to trains
4196  {
4197  GraphicOutput = RailGraphics->LCBothHor;
4198  }
4199  else // plot as closed to trains if in any other state
4200  {
4201  GraphicOutput = RailGraphics->LCBothVer;
4202  }
4203  }
4204  else // vert element
4205  {
4206  if(Next.Attribute == 1) // open to trains
4207  {
4208  GraphicOutput = RailGraphics->LCBothVer;
4209  }
4210  else // plot as closed to trains if in any other state
4211  {
4212  GraphicOutput = RailGraphics->LCBothHor;
4213  }
4214  }
4215  }
4216  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4217  }
4218  }
4219 
4220  TextHandler->WriteTextToImage(1, Bitmap); //added at v2.10.0
4221 
4222  NextTrackElementPtr = TrackVector.begin();
4223  while(ReturnNextTrackElement(3, Next))
4224  {
4225  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4226  {
4227  if(Next.TrackType == Points) // plot active fillet
4228  {
4229  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4230  if(Next.SpeedTag < 28)
4231  {
4232  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4234  }
4235  else if(Next.SpeedTag < 132)
4236  {
4237  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4239  }
4240  else
4241  {
4242  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4244  }
4245  }
4246  else if(Next.TrackType == GapJump) // plot as connected
4247  {
4248  if(Next.SpeedTag == 88)
4249  {
4250  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4251  }
4252  else if(Next.SpeedTag == 89)
4253  {
4254  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4255  }
4256  else if(Next.SpeedTag == 90)
4257  {
4258  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4259  }
4260  else if(Next.SpeedTag == 91)
4261  {
4262  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4263  }
4264  else if(Next.SpeedTag == 92)
4265  {
4266  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4267  }
4268  else if(Next.SpeedTag == 93)
4269  {
4270  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4271  }
4272  else if(Next.SpeedTag == 94)
4273  {
4274  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4275  }
4276  else if(Next.SpeedTag == 95)
4277  {
4278  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4279  }
4280  }
4281  else if(Next.TrackType == SignalPost) // plot in correct colour
4282  {
4283  for(int x = 0; x < 40; x++)
4284  {
4285  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4286  {
4287  // plot blank first, then plot platform if present - (always not striped for operating railway)
4288  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4289  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4290  int HOffset = 0;
4291  if(Next.SpeedTag > 73)
4292  {
4293  HOffset = 5;
4294  }
4295  else if(Next.SpeedTag == 71)
4296  {
4297  HOffset = 9;
4298  }
4299  int VOffset = 0;
4300  if(Next.SpeedTag == 69)
4301  {
4302  VOffset = 9;
4303  }
4304  else if(Next.SpeedTag == 72)
4305  {
4306  VOffset = 5;
4307  }
4308  else if(Next.SpeedTag == 74)
4309  {
4310  VOffset = 5;
4311  }
4312  Graphics::TBitmap *GraphicPtr;
4313  if(Next.SpeedTag > 71)
4314  {
4315  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4316  }
4317  else if(Next.SpeedTag < 70)
4318  {
4319  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4320  }
4321  else
4322  {
4323  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4324  }
4325  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4326  // plot special signal platform if present
4327  Graphics::TBitmap* SignalPlatformGraphic;
4328  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4329  {
4330  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4331  }
4332  // now plot signal (double yellow overwrites most of signal platform if present)
4333  // below amended for version 0.6
4335  {
4336  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4337  }
4338  else if(Next.SigAspect == TTrackElement::TwoAspect)
4339  {
4340  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4341  }
4342  else if(Next.SigAspect == TTrackElement::GroundSignal)
4343  {
4344  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4345  }
4346  else // 4 aspect
4347  {
4348  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4349  }
4350  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4351  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4352  {
4353  if(Next.SpeedTag == 68)
4354  {
4355  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4356  }
4357  if(Next.SpeedTag == 69)
4358  {
4359  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4360  }
4361  if(Next.SpeedTag == 70)
4362  {
4363  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4364  }
4365  if(Next.SpeedTag == 71)
4366  {
4367  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4368  }
4369  if(Next.SpeedTag == 72)
4370  {
4371  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4372  }
4373  if(Next.SpeedTag == 73)
4374  {
4375  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4376  }
4377  if(Next.SpeedTag == 74)
4378  {
4379  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4380  }
4381  if(Next.SpeedTag == 75)
4382  {
4383  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4384  }
4385  }
4386  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4387  {
4388  for(int x = 0; x < 40; x++)
4389  {
4390  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4391  {
4392  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4393  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4394  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4395  // plot special signal platform if present
4396  Graphics::TBitmap* SignalPlatformGraphic;
4397  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4398  {
4399  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4400  }
4401  // now plot signal
4402  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4403  break;
4404  }
4405  }
4406  }
4407  break;
4408  }
4409  }
4410  }
4411  else
4412  {
4413  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4414  }
4415  }
4416  }
4417  if(OldTransparentColour != clB5G5R5)
4418  {
4419  Utilities->clTransparent = OldTransparentColour; // restore
4422  }
4423  Utilities->CallLogPop(1701);
4424 }
4425 
4426 // ---------------------------------------------------------------------------
4427 
4428 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4429 {
4430  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4431  for(unsigned int x = 0; x < TrackVector.size(); x++)
4432  {
4433  if(TrackElementAt(1093, x).TrackType == GapJump)
4434  {
4435  if(TrackElementAt(1094, x).Conn[0] > -1)
4436  {
4437  continue; // to next 'x' value as this element has already been set
4438  }
4439  // here if identify a GapJump element not yet set
4440  GapPos = x;
4441  GapHLoc = TrackElementAt(1095, x).HLoc;
4442  GapVLoc = TrackElementAt(1096, x).VLoc;
4443  // highlight it
4445  Utilities->CallLogPop(469);
4446  return(true);
4447  }
4448  }
4449  Utilities->CallLogPop(470);
4450  return(false);
4451 }
4452 
4453 // ---------------------------------------------------------------------------
4454 
4455 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4456 {
4457  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4458  AnsiString(VLoc));
4459  int Position;
4460  TTrackElement TrackElement;
4461 
4462  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4463  {
4464  Utilities->CallLogPop(471);
4465  return(false); // not found
4466  }
4467  if(TrackElement.TrackType != GapJump)
4468  {
4469  Utilities->CallLogPop(472);
4470  return(false); // found something but not a gap
4471  }
4472  if(Position == GapPos)
4473  {
4474  Utilities->CallLogPop(473);
4475  return(false); // selected original gap
4476  }
4477  if(TrackElementAt(1097, Position).Conn[0] != -1)
4478  {
4479  Utilities->CallLogPop(474);
4480  return(false); // already selected
4481  }
4482  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4483  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4484  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4485  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4486 // now highlight the selected location
4487  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4488  Utilities->CallLogPop(475);
4489  return(true);
4490 }
4491 
4492 // ---------------------------------------------------------------------------
4493 
4494 bool TTrack::GapsUnset(int Caller)
4495 // returns true if there are gaps and any are unset
4496 {
4497  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4498  if(TrackVector.size() == 0)
4499  {
4500  Utilities->CallLogPop(476);
4501  return(false);
4502  }
4503  for(unsigned int x = 0; x < TrackVector.size(); x++)
4504  {
4505  if(TrackElementAt(1102, x).TrackType == GapJump)
4506  {
4507  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4508  {
4509  Utilities->CallLogPop(477);
4510  return(true);
4511  }
4512  else // set, but may not have matching element, or that element may not be set
4513  {
4514  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4515  // check that the element pointed to by the gap link is a GapJump
4516  {
4517  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4518  Utilities->CallLogPop(1137);
4519  return(false);
4520  }
4521 // here if gap connection is itself a GapJump
4522  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4523  // check that the element pointed to by the gap link is a GapJump & that its gap link
4524  // points back to 'x'
4525  {
4526  Utilities->CallLogPop(478);
4527  return(true);
4528  }
4529 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4530  }
4531  } // if(TrackElementAt(, x).TrackType == GapJump)
4532 
4533  } // for x...
4534  Utilities->CallLogPop(479);
4535  return(false);
4536 }
4537 
4538 // ---------------------------------------------------------------------------
4539 
4540 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4541 {
4542  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4543  for(unsigned int x = 0; x < TrackVector.size(); x++)
4544  {
4545  if(TrackElementAt(1110, x).TrackType == GapJump)
4546  {
4547  Utilities->CallLogPop(1105);
4548  return(false);
4549  }
4550  }
4551  Utilities->CallLogPop(1106);
4552  return(true);
4553 }
4554 
4555 // ---------------------------------------------------------------------------
4556 
4557 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4558 {
4559  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4560  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4561  {
4562  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4563  {
4564  Utilities->CallLogPop(1107);
4565  return(false);
4566  }
4567  }
4568  for(unsigned int x = 0; x < TrackVector.size(); x++)
4569  {
4570  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4571  {
4572  Utilities->CallLogPop(1108);
4573  return(false);
4574  }
4575  }
4576  Utilities->CallLogPop(1109);
4577  return(true);
4578 }
4579 
4580 // ---------------------------------------------------------------------------
4581 
4583 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4584 // returns false otherwise or if there are no NamedLocationElements
4585 {
4586  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4587  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4588  {
4589  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4590  {
4591  if(InactiveTrackElementAt(139, x).LocationName == "")
4592  {
4593  Utilities->CallLogPop(1110);
4594  return(true);
4595  }
4596  }
4597  }
4598  for(unsigned int x = 0; x < TrackVector.size(); x++)
4599  {
4600  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4601  {
4602  if(TrackElementAt(1113, x).LocationName == "")
4603  {
4604  Utilities->CallLogPop(1111);
4605  return(true);
4606  }
4607  }
4608  }
4609  Utilities->CallLogPop(1112);
4610  return(false);
4611 }
4612 
4613 // ---------------------------------------------------------------------------
4614 
4615 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4616 {
4617  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4618  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4619  Utilities->CallLogPop(480);
4620 }
4621 
4622 // ---------------------------------------------------------------------------
4623 
4625 {
4626  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4627  if(TrackVector.size() == 0)
4628  {
4629  Utilities->CallLogPop(481);
4630  return;
4631  }
4632  for(unsigned int x = 0; x < TrackVector.size(); x++)
4633  {
4634  if(TrackElementAt(1114, x).TrackType == GapJump)
4635  {
4636  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4637  {
4638  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4639  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4640  {
4641  TrackElementAt(1118, x).Conn[0] = -1;
4642  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4643  continue; // to next 'x'
4644  }
4645 // here if gap connection is itself a GapJump
4646  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4647  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4648  // if not clear Conns & CLks
4649  {
4650  TrackElementAt(1121, x).Conn[0] = -1;
4651  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4652  continue; // to next 'x'
4653  }
4654 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4655 // hence no more action needed on these Conns & CLks
4656  }
4657  } // else //gap jump
4658 
4659  } // for x...
4660 // throw Exception("Test Exception");//test
4661  Utilities->CallLogPop(482);
4662 }
4663 
4664 // ---------------------------------------------------------------------------
4665 
4666 void TTrack::ResetSignals(int Caller)
4667 {
4668  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4669  for(unsigned int x = 0; x < TrackVector.size(); x++)
4670  {
4671  if(TrackElementAt(1123, x).TrackType == SignalPost)
4672  {
4673  TrackElementAt(1124, x).Attribute = 0;
4674  }
4675  }
4676  Utilities->CallLogPop(483);
4677 }
4678 
4679 // ---------------------------------------------------------------------------
4680 
4681 void TTrack::ResetPoints(int Caller)
4682 {
4683  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4684  for(unsigned int x = 0; x < TrackVector.size(); x++)
4685  {
4686  if(TrackElementAt(1125, x).TrackType == Points)
4687  {
4688  TrackElementAt(1126, x).Attribute = 0;
4689  }
4690  }
4691  Utilities->CallLogPop(484);
4692 }
4693 
4694 // ---------------------------------------------------------------------------
4695 
4696 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4697 {
4698  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4699  if(TrackVector.empty())
4700  {
4701  TrackMap.clear();
4702  Utilities->CallLogPop(485);
4703  return(true);
4704  }
4705 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4706  THVPair TrackMapKeyPair;
4707 
4708  NewVector.clear();
4709  TTrackMapIterator TrackMapPtr;
4710 
4711  if(!TrackMap.empty())
4712  {
4713  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4714  {
4715  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4716  }
4717  }
4718  if(NewVector.size() != TrackMap.size())
4719  {
4720  throw Exception("Error - Map & Vector different sizes");
4721  }
4722  unsigned int NonZeroCount = 0;
4723 
4724  for(unsigned int x = 0; x < TrackVector.size(); x++)
4725  {
4726  if(TrackElementAt(1127, x).TrackType != Erase)
4727  {
4728  NonZeroCount++;
4729  }
4730  }
4731  if(NewVector.size() != NonZeroCount)
4732  {
4733  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4734  }
4736  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4737  TTrackMapEntry TrackMapEntry;
4738 
4739  for(unsigned int x = 0; x < TrackVector.size(); x++)
4740  {
4741  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4742  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4743  TrackMapEntry.first = TrackMapKeyPair;
4744  TrackMapEntry.second = x;
4745  if(!(TrackMap.insert(TrackMapEntry).second))
4746  {
4747  throw Exception("Error - map insertion failure, TrackVector in error");
4748  }
4749  }
4750 // All track now relocated in TrackVector, reset all Conns & CLks
4751  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4752  {
4753  for(unsigned int y = 0; y < 4; y++)
4754  {
4755  TrackElementAt(1130, x).Conn[y] = -1;
4756  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4757  }
4758  }
4759  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4760  CheckMapAndTrack(4); // test
4761  CheckMapAndInactiveTrack(4); // test
4762  CheckLocationNameMultiMap(8); // test
4763  if(!ResetGapsFromGapMap(1))
4764  {
4765  Utilities->CallLogPop(489);
4766  return(false);
4767  }
4768  Utilities->CallLogPop(490);
4769  return(true);
4770 }
4771 
4772 // ---------------------------------------------------------------------------
4773 
4774 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4775 {
4776  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4777  GapMap.clear();
4778  THVPair GapMapKeyPair, GapMapValuePair;
4779  TGapMapEntry GapMapEntry;
4780 
4781  for(unsigned int x = 0; x < TrackVector.size(); x++)
4782  {
4783  if(TrackElementAt(1132, x).TrackType == GapJump)
4784  {
4785  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
4786  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
4787  GapMapEntry.first = GapMapKeyPair;
4788  if(TrackElementAt(1135, x).Conn[0] == -1)
4789  {
4790  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4791  }
4792  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
4793  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
4794  GapMapEntry.second = GapMapValuePair;
4795  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4796  {
4797  GapMap.insert(GapMapEntry);
4798  }
4799  }
4800  }
4801  Utilities->CallLogPop(492);
4802 }
4803 
4804 // ---------------------------------------------------------------------------
4805 
4806 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4807 {
4808  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4809 
4810 //1st pass to check track element locations - split into 2 passes at v2.11.1 so positioning checked before linkages, requested by Dan(#4669) 18/12/21 via Discord
4811  LocError = false;
4812  bool TrackElementPositionsOK = true;
4813 
4814  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4815  {
4816  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
4817  {
4818  continue; // skip blank elements
4819  }
4820 // check footcrossing linkages
4821  if(TrackElementAt(1139, x).TrackType == FootCrossing)
4822  {
4823  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
4824  {
4825  ShowMessage(
4826  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4827  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4828  "can't connect to an underpass or vice versa)");
4829  HLoc = TrackElementAt(1141, x).HLoc;
4830  VLoc = TrackElementAt(1142, x).VLoc;
4831  LocError = true;
4832  Utilities->CallLogPop(493);
4833  return(false);
4834  }
4835  }
4836  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4837  {
4838  if(TrackElementAt(1143, x).Link[y] <= 0)
4839  {
4840  continue; // no link
4841  }
4842  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
4843  {
4844  continue; // buffer
4845  }
4846  if(TrackElementAt(1146, x).Config[y] == Gap)
4847  {
4848  continue; // gaps set later from GapMap
4849  }
4850  // get required H & V for track element joining link 'y'
4851  int NewHLoc = TrackElementAt(1437, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
4852  int NewVLoc = TrackElementAt(1438, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
4853  // find track element if present
4854  bool ConnectionFoundFlag;
4855  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4856  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4857  {
4858  ShowMessage("Can't have a track element adjacent to a continuation exit");
4859  HLoc = TrackElementAt(1152, x).HLoc;
4860  VLoc = TrackElementAt(1153, x).VLoc;
4861  LocError = true;
4862  if(FinalCall)
4863  {
4864  throw Exception("Error in final track linkage - continuation adjacent to another element");
4865  }
4866  Utilities->CallLogPop(1539);
4867  return(false);
4868  }
4869  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
4870  {
4871  continue;
4872  }
4873  if(ConnectionFoundFlag)
4874  {
4875  TrackElementAt(1156, x).Conn[y] = VecPos; //<-- this sets the Conn value
4876  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4877  if((TrackElementAt(1157, x).Config[1 - y] == Signal) && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
4878  {
4879  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4880  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4881  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4882  TrackElementPositionsOK = false;
4883  }
4884  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
4885  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
4886  {
4887  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4888  // need room for a train (2 elements) without fouling points or signals
4889  TrackElementPositionsOK = false;
4890  }
4891  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
4892  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
4893  {
4894  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
4895  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
4896  // if continuation next to a signal; also none of these can be a named location, and a continuation can
4897  // be named but needs the adjacent element named too
4898  TrackElementPositionsOK = false;
4899  }
4900  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
4901  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
4902  {
4903  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
4904  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4905  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4906  TrackElementPositionsOK = false;
4907  }
4908  else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
4909  {
4910  ShowMessage("Signal facing a bridge - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
4911  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4912  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4913  TrackElementPositionsOK = false;
4914  }
4915  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
4916  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4917  {
4918  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
4919  TrackElementPositionsOK = false;
4920  }
4921  // if failed then set the invert values for the offending element
4922  if(!TrackElementPositionsOK)
4923  {
4924  HLoc = TrackElementAt(1183, x).HLoc;
4925  VLoc = TrackElementAt(1184, x).VLoc;
4926  LocError = true;
4927  if(FinalCall)
4928  {
4929  throw Exception("Error in track element positions in FinalCall");
4930  }
4931  Utilities->CallLogPop(494);
4932  return(false);
4933  }
4934  }
4935  // no 'else' here, if there's no link then will be picked up in 2nd pass
4936  }
4937  } // for(unsigned int x=0;x<TrackVector.size();x++)
4938 
4939 
4940 //2nd pass - looking for missing connections
4941  LocError = false;
4942  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4943  {
4944  if(TrackElementAt(1439, x).TrackType == Erase) //Erase isn't used any more as a track type
4945  {
4946  continue; // skip blank elements
4947  }
4948  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4949  {
4950  if(TrackElementAt(1440, x).Link[y] <= 0)
4951  {
4952  continue; // no link
4953  }
4954  if((TrackElementAt(1441, x).TrackType == Buffers) && (TrackElementAt(1442, x).Config[y] == End))
4955  {
4956  continue; // buffer
4957  }
4958  if(TrackElementAt(1443, x).Config[y] == Gap)
4959  {
4960  continue; // gaps set later from GapMap
4961  }
4962  if((TrackElementAt(1444, x).TrackType == Continuation) && (TrackElementAt(1445, x).Config[y] == End))
4963  {
4964  continue; //continuation
4965  }
4966  // get required H & V for track element joining link 'y'
4967  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1448, x).Link[y]][0];
4968  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1449, x).Link[y]][1];
4969  // find track element if present
4970  bool ConnectionFoundFlag;
4971  bool LinkMatchFound = false;
4972  int VecPos = GetVectorPositionFromTrackMap(66, NewHLoc, NewVLoc, ConnectionFoundFlag);
4973  // if there isn't a connection set the invert values for the offending element
4974  if(ConnectionFoundFlag) //set the ConnLinkPos values
4975  {
4976  for(unsigned int a = 0; a < 4; a++)
4977  {
4978  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
4979  (TrackElementAt(1181, VecPos).Config[a] != Gap))
4980  {
4981  TrackElementAt(1182, x).ConnLinkPos[y] = a;
4982  // note - this ensures that if the connecting element is a leading point
4983  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4984  // (Points have the same link value for both [0] and [2])
4985  LinkMatchFound = true;
4986  break; // stop after first find or will find later link for leading point
4987  }
4988  }
4989  if(!LinkMatchFound)
4990  {
4991  HLoc = TrackElementAt(1446, x).HLoc;
4992  VLoc = TrackElementAt(1447, x).VLoc;
4993  LocError = true;
4994  if(FinalCall)
4995  {
4996  throw Exception("Error in final track linkage - - no matching link found");
4997  }
4998  Utilities->CallLogPop(495);
4999  return(false);
5000  }
5001  }
5002  else //error
5003  {
5004  HLoc = TrackElementAt(1185, x).HLoc;
5005  VLoc = TrackElementAt(1186, x).VLoc;
5006  LocError = true;
5007  if(FinalCall)
5008  {
5009  throw Exception("Error in final track linkage - connection not found");
5010  }
5011  Utilities->CallLogPop(2443);
5012  return(false);
5013  }
5014  }
5015  }
5016 //end of 2nd pass
5017 
5018  if(FinalCall)
5019  {
5021  }
5022 
5023 // confirmatiory checks that all ok - or throw error
5024  bool ConnErrorFlag = false;
5025 
5026  for(unsigned int x = 0; x < TrackVector.size(); x++)
5027  {
5028  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
5029  {
5030  ConnErrorFlag = true;
5031  }
5032  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
5033  {
5034  ConnErrorFlag = true;
5035  }
5036  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
5037  {
5038  ConnErrorFlag = true;
5039  }
5040  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
5041  {
5042  ConnErrorFlag = true;
5043  }
5044  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5045  {
5046  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
5047  {
5048  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1))
5049  {
5050  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5051  }
5052  }
5053  }
5054  }
5055  if(ConnErrorFlag)
5056  {
5057  if(FinalCall)
5058  {
5059  throw Exception("ConnError in LinkTrack - Final");
5060  }
5061  else
5062  {
5063  throw Exception("ConnError in LinkTrack - Precheck");
5064  }
5065  }
5066  bool CLkErrorFlag = false;
5067 
5068  for(unsigned int x = 0; x < TrackVector.size(); x++)
5069  {
5070  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
5071  {
5072  CLkErrorFlag = true;
5073  }
5074  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
5075  {
5076  CLkErrorFlag = true;
5077  }
5078  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
5079  {
5080  CLkErrorFlag = true;
5081  }
5082  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
5083  {
5084  CLkErrorFlag = true;
5085  }
5086  }
5087 
5088  if(CLkErrorFlag)
5089  {
5090  if(FinalCall)
5091  {
5092  throw Exception("CLkError in LinkTrack - Final");
5093  }
5094  else
5095  {
5096  throw Exception("CLkError in LinkTrack - Precheck");
5097  }
5098  }
5099 
5100 // set element lengths to min of 10m
5101  for(unsigned int x = 0; x < TrackVector.size(); x++)
5102  {
5103  if(TrackElementAt(1214, x).TrackType == Erase)
5104  {
5105  continue; // skip blank elements
5106  }
5107  if((TrackElementAt(1215, x).Length01 < 10) && (TrackElementAt(1435, x).Length01 != -1))
5108  {
5109  TrackElementAt(1216, x).Length01 = 10;
5110  }
5111  if((TrackElementAt(1217, x).Length23 < 10) && (TrackElementAt(1218, x).Length23 != -1))
5112  {
5113  TrackElementAt(1219, x).Length23 = 10;
5114  }
5115  }
5116 
5117  if(FinalCall) // ONLY at FinalCall, no point calling twice
5118  {
5119  CalcHLocMinEtc(3);
5120  }
5121 
5122  Utilities->CallLogPop(497);
5123  return(true);
5124 }
5125 
5126 // ---------------------------------------------------------------------------
5127 
5128 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
5129 {
5130  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
5131  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5132  {
5133  if(TrackElementAt(1220, x).TrackType == Erase)
5134  {
5135  continue; // skip blank elements
5136 
5137  }
5138 // check footcrossing linkages
5139  if(TrackElementAt(1221, x).TrackType == FootCrossing)
5140  {
5141  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
5142  {
5143  Utilities->CallLogPop(1127);
5144  return(false);
5145  }
5146  }
5147  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5148  {
5149  if(TrackElementAt(1223, x).Link[y] <= 0)
5150  {
5151  continue; // no link
5152  }
5153  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5154  {
5155  continue; // buffer
5156  }
5157  if(TrackElementAt(1226, x).Config[y] == Gap)
5158  {
5159  continue; // gaps set later from GapMap
5160 
5161  }
5162  // get required H & V for track element joining link 'y'
5163  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5164  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5165  // find track element if present
5166  bool ConnectionFoundFlag;
5167  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5168  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5169  {
5170  if(FinalCall)
5171  {
5172  throw Exception("Error in final track linkage - continuation adjacent to another element");
5173  }
5174  Utilities->CallLogPop(1540);
5175  return(false);
5176  }
5177  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5178  {
5179  continue;
5180  }
5181  if(ConnectionFoundFlag)
5182  {
5183  TrackElementAt(1234, x).Conn[y] = VecPos;
5184  bool LinkFoundFlag = false;
5185  // find connecting link in the newly found track element if there is one & make checks
5186  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5187  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5188  {
5189  Utilities->CallLogPop(1541);
5190  return(false);
5191  }
5192  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5193  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5194  {
5195  Utilities->CallLogPop(1542);
5196  return(false);
5197  }
5198  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5199  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5200  {
5201  Utilities->CallLogPop(1543);
5202  return(false);
5203  }
5204  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5205  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5206  {
5207  Utilities->CallLogPop(1981);
5208  return(false);
5209  }
5210 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5211  else if(TrackElementAt(, x).TrackType == Continuation)
5212  {
5213  int H = TrackElementAt(, x).HLoc;
5214  int V = TrackElementAt(, x).VLoc;
5215  bool FoundFlag = false;
5216  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5217  if(FoundFlag)
5218  {
5219  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5220  {
5221  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5222  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5223  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5224  if(FoundFlag)
5225  {
5226  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5227  {
5228  Utilities->CallLogPop();
5229  return false;
5230  }
5231  }
5232  else
5233  {
5234  Utilities->CallLogPop();
5235  return false;
5236  }
5237  }
5238  }
5239  }
5240 */
5241  for(unsigned int a = 0; a < 4; a++)
5242  {
5243  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5244  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5245  {
5246  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5247  // note - this ensures that if the connecting element is a leading point
5248  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5249  // (Points have the same link value for both [0] and [2])
5250  LinkFoundFlag = true;
5251  break; // stop after first find or will find later link for leading point
5252  }
5253  }
5254  if(!LinkFoundFlag)
5255  {
5256  if(FinalCall)
5257  {
5258  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5259  }
5260  Utilities->CallLogPop(1128);
5261  return(false);
5262  }
5263  }
5264  else // if(ConnectionFoundFlag)
5265  {
5266  if(FinalCall)
5267  {
5268  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5269  }
5270  Utilities->CallLogPop(1129);
5271  return(false);
5272  }
5273  }
5274  } // for(unsigned int x=0;x<TrackVector.size();x++)
5275 
5276  if(FinalCall)
5277  {
5279  }
5280 // final check
5281  bool ConnErrorFlag = false;
5282 
5283  for(unsigned int x = 0; x < TrackVector.size(); x++)
5284  {
5285  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5286  {
5287  ConnErrorFlag = true;
5288  }
5289  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5290  {
5291  ConnErrorFlag = true;
5292  }
5293  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5294  {
5295  ConnErrorFlag = true;
5296  }
5297  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5298  {
5299  ConnErrorFlag = true;
5300  }
5301  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5302  {
5303  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5304  {
5305  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1))
5306  {
5307  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5308  }
5309  }
5310  }
5311  }
5312  if(ConnErrorFlag)
5313  {
5314  if(FinalCall)
5315  {
5316  throw Exception("ConnError in LinkTrack - Final");
5317  }
5318  else
5319  {
5320  throw Exception("ConnError in LinkTrack - Precheck");
5321  }
5322  }
5323  bool CLkErrorFlag = false;
5324 
5325  for(unsigned int x = 0; x < TrackVector.size(); x++)
5326  {
5327  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5328  {
5329  CLkErrorFlag = true;
5330  }
5331  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5332  {
5333  CLkErrorFlag = true;
5334  }
5335  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5336  {
5337  CLkErrorFlag = true;
5338  }
5339  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5340  {
5341  CLkErrorFlag = true;
5342  }
5343  }
5344 
5345  if(CLkErrorFlag)
5346  {
5347  if(FinalCall)
5348  {
5349  throw Exception("CLkError in LinkTrack - Final");
5350  }
5351  else
5352  {
5353  throw Exception("CLkError in LinkTrack - Precheck");
5354  }
5355  }
5356 // set element lengths to min of 10m
5357  for(unsigned int x = 0; x < TrackVector.size(); x++)
5358  {
5359  if(TrackElementAt(1284, x).TrackType == Erase)
5360  {
5361  continue; // skip blank elements
5362  }
5363  if((TrackElementAt(1285, x).Length01 < 10) && (TrackElementAt(1436, x).Length23 != -1))
5364  {
5365  TrackElementAt(1286, x).Length01 = 10;
5366  }
5367  if((TrackElementAt(1287, x).Length23 < 10) && (TrackElementAt(1288, x).Length23 != -1))
5368  {
5369  TrackElementAt(1289, x).Length23 = 10;
5370  }
5371  }
5372 
5373  if(FinalCall) // ONLY at FinalCall, no point calling twice
5374  {
5375  CalcHLocMinEtc(7);
5376  }
5377  Utilities->CallLogPop(1130);
5378  return(true);
5379 }
5380 
5381 // ---------------------------------------------------------------------------
5382 
5383 bool TTrack::IsTrackLinked(int Caller) // not used any more
5384 {
5385  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5386  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5387  {
5388  if(TrackElementAt(1290, x).TrackType == Erase)
5389  {
5390  Utilities->CallLogPop(498);
5391  return(false);
5392  }
5393 // check foot linkages
5394  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5395  {
5396  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5397  {
5398  Utilities->CallLogPop(499);
5399  return(false);
5400  }
5401  }
5402  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5403  {
5404  if(TrackElementAt(1293, x).Link[y] <= 0)
5405  {
5406  continue; // no link
5407  }
5408  if(TrackElementAt(1294, x).Config[y] == End)
5409  {
5410  continue; // buffer or continuation
5411  }
5412  if(TrackElementAt(1295, x).Config[y] == Gap)
5413  {
5414  continue; // gaps set later from GapMap
5415 
5416  }
5417  // get required H & V for track element joining link 'y'
5418  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5419  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5420  // find track element if present
5421  bool ConnectionFoundFlag = false;
5422  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5423  if(ConnectionFoundFlag)
5424  {
5425  TrackElementAt(1300, x).Conn[y] = VecPos;
5426  // find connecting link in the newly found track element if there is one & make buffer check
5427  bool LinkFoundFlag = false;
5428  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5429  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5430  {
5431  Utilities->CallLogPop(500);
5432  return(false);
5433  }
5434  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5435  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5436  {
5437  Utilities->CallLogPop(501);
5438  return(false);
5439  }
5440  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5441  {
5442  Utilities->CallLogPop(502);
5443  return(false);
5444  }
5445  else
5446  {
5447  for(unsigned int a = 0; a < 4; a++)
5448  {
5449  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5450  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5451  {
5452  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5453  // note - this ensures that if the connecting element is a leading point
5454  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5455  // (Points have the same link value for both [0] and [2])
5456  LinkFoundFlag = true;
5457  break; // stop after first find or will find later link for leading point
5458  }
5459  }
5460  }
5461  if(!LinkFoundFlag)
5462  {
5463  Utilities->CallLogPop(503);
5464  return(false);
5465  }
5466  }
5467  else // if(ConnectionFoundFlag)
5468  {
5469  Utilities->CallLogPop(504);
5470  return(false);
5471  }
5472  }
5473  } // for(unsigned int x=0;x<TrackVector.size();x++)
5474 
5475 // final check
5476  bool ConnErrorFlag = false;
5477 
5478  for(unsigned int x = 0; x < TrackVector.size(); x++)
5479  {
5480  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5481  {
5482  ConnErrorFlag = true;
5483  }
5484  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5485  {
5486  ConnErrorFlag = true;
5487  }
5488  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5489  {
5490  ConnErrorFlag = true;
5491  }
5492  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5493  {
5494  ConnErrorFlag = true;
5495  }
5496  }
5497  if(ConnErrorFlag)
5498  {
5499  Utilities->CallLogPop(505);
5500  return(false);
5501  }
5502  bool CLkErrorFlag = false;
5503 
5504  for(unsigned int x = 0; x < TrackVector.size(); x++)
5505  {
5506  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5507  {
5508  CLkErrorFlag = true;
5509  }
5510  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5511  {
5512  CLkErrorFlag = true;
5513  }
5514  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5515  {
5516  CLkErrorFlag = true;
5517  }
5518  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5519  {
5520  CLkErrorFlag = true;
5521  }
5522  }
5523 
5524  if(CLkErrorFlag)
5525  {
5526  Utilities->CallLogPop(506);
5527  return(false);
5528  }
5529  Utilities->CallLogPop(507);
5530  return(true);
5531 }
5532 
5533 // ---------------------------------------------------------------------------
5534 
5536 {
5537  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5538  int Position1, Position2;
5539  TTrackElement TrackElement1, TrackElement2;
5540  TGapMapIterator GapMapPtr;
5541 
5542  if(!GapMap.empty())
5543  {
5544  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5545  {
5546  int HLoc1 = GapMapPtr->first.first;
5547  int VLoc1 = GapMapPtr->first.second;
5548  int HLoc2 = GapMapPtr->second.first;
5549  int VLoc2 = GapMapPtr->second.second;
5550  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5551  {
5552  throw Exception("Failed to find H & V for gap1, GapMap in error");
5553  }
5554  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5555  {
5556  throw Exception("Failed to find H & V for gap2, GapMap in error");
5557  }
5558  if(TrackElementAt(9, Position1).TrackType != GapJump)
5559  {
5560  throw Exception("Element at Pos1 not a gap, GapMap in error");
5561  }
5562  if(TrackElementAt(10, Position2).TrackType != GapJump)
5563  {
5564  throw Exception("Element at Pos2 not a gap, GapMap in error");
5565  }
5566  TrackElementAt(11, Position1).Conn[0] = Position2;
5567  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5568  TrackElementAt(13, Position2).Conn[0] = Position1;
5569  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5570  }
5571  }
5572  Utilities->CallLogPop(510);
5573  return(true);
5574 }
5575 
5576 // ---------------------------------------------------------------------------
5577 
5578 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5579 {
5580 // TIMPair MapEntry;
5581  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5582  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5583  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5584  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5585  TLocationNameMultiMapEntry LocationNameEntry;
5586 
5587  LocationNameEntry.first = TrackElement.LocationName;
5588  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5589  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5590  {
5591 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5592 // could arise when loading old railways with multiple NonStationNamedLocs
5593  bool FoundFlag = false;
5594  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5595  if(FoundFlag)
5596  {
5597  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5598  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5599  {
5600  Utilities->CallLogPop(1813);
5601  return;
5602  }
5603  }
5604  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5605  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5606  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5607  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5608  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5609  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5610  if(TrackElement.FixedNamedLocationElement)
5611  {
5612  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5613  LocationNameMultiMap.insert(LocationNameEntry);
5614  }
5615  if(TrackElement.HLoc < HLocMin)
5616  {
5617  HLocMin = TrackElement.HLoc;
5618  }
5619  if(TrackElement.HLoc > HLocMax)
5620  {
5621  HLocMax = TrackElement.HLoc;
5622  }
5623  if(TrackElement.VLoc < VLocMin)
5624  {
5625  VLocMin = TrackElement.VLoc;
5626  }
5627  if(TrackElement.VLoc > VLocMax)
5628  {
5629  VLocMax = TrackElement.VLoc;
5630  }
5631  }
5632  else
5633  {
5634 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5635 // shouldn't arise but leave in as a safeguard
5636  bool FoundFlag = false;
5637  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5638  if(FoundFlag)
5639  {
5640  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5641  {
5642  Utilities->CallLogPop(1814);
5643  return;
5644  }
5645  }
5646  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5647  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5648  {
5649  TrackMapKeyPair.first = TrackElement.HLoc;
5650  TrackMapKeyPair.second = TrackElement.VLoc;
5651  TrackMapEntry.first = TrackMapKeyPair;
5652  TrackMapEntry.second = TrackVector.size() - 1;
5653  TrackMap.insert(TrackMapEntry);
5654  if(TrackElement.FixedNamedLocationElement)
5655  {
5656  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5657  LocationNameMultiMap.insert(LocationNameEntry);
5658  }
5659  if(TrackElement.HLoc < HLocMin)
5660  {
5661  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5662  }
5663  if(TrackElement.HLoc > HLocMax)
5664  {
5665  HLocMax = TrackElement.HLoc;
5666  }
5667  if(TrackElement.VLoc < VLocMin)
5668  {
5669  VLocMin = TrackElement.VLoc;
5670  }
5671  if(TrackElement.VLoc > VLocMax)
5672  {
5673  VLocMax = TrackElement.VLoc;
5674  }
5675  }
5676  }
5677 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5678 // CheckMapAndInactiveTrack(6);//test
5679 
5680 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5681 // with the Platforms until layout fully loaded
5682  Utilities->CallLogPop(511);
5683 }
5684 
5685 // ---------------------------------------------------------------------------
5686 
5687 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5688 {
5689  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5690  AnsiString(VLoc));
5691  THVPair TrackMapKeyPair;
5692 
5693  FoundFlag = false;
5694  TTrackMapIterator TrackMapPtr;
5695 
5696  TrackMapKeyPair.first = HLoc;
5697  TrackMapKeyPair.second = VLoc;
5698  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5699  if(TrackMapPtr == TrackMap.end())
5700  {
5701  Utilities->CallLogPop(512);
5702  return(-1); // nothing found
5703  }
5704  else
5705  {
5706  FoundFlag = true;
5707  Utilities->CallLogPop(513);
5708  return(TrackMapPtr->second);
5709  }
5710 }
5711 
5712 // ---------------------------------------------------------------------------
5713 
5714 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5715 {
5716  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5717  AnsiString(VLoc));
5718  THVPair TrackMapKeyPair;
5719  TTrackMapIterator TrackMapPtr;
5720 
5721  TrackMapKeyPair.first = HLoc;
5722  TrackMapKeyPair.second = VLoc;
5723  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5724  if(TrackMapPtr == TrackMap.end())
5725  {
5726  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5727  throw Exception(Message);
5728  }
5729  else
5730  {
5731  Utilities->CallLogPop(1943);
5732  return(TrackElementAt(871, TrackMapPtr->second));
5733  }
5734 }
5735 
5736 // ---------------------------------------------------------------------------
5737 
5738 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5739 { //modded at v2.9.2 to make Map & Vector references
5740  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5741  AnsiString(VLoc));
5742  THVPair MapKeyPair;
5743  TTrackMapIterator MapPtr;
5744 
5745  MapKeyPair.first = HLoc;
5746  MapKeyPair.second = VLoc;
5747  MapPtr = Map.find(MapKeyPair);
5748  if(MapPtr == Map.end())
5749  {
5750  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5751  throw Exception(Message);
5752  }
5753  else
5754  {
5755  Utilities->CallLogPop(2280);
5756  return(Vector.at(MapPtr->second));
5757  }
5758 }
5759 
5760 // ---------------------------------------------------------------------------
5761 
5763 {
5764  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5765  AnsiString(VLoc));
5766  THVPair InactiveTrackMapKeyPair;
5767  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5768 
5769  InactiveTrackMapKeyPair.first = HLoc;
5770  InactiveTrackMapKeyPair.second = VLoc;
5771  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5772  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5773  {
5774  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5775  throw Exception(Message);
5776  }
5777  else
5778  {
5779  Utilities->CallLogPop(1949);
5780  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5781  }
5782 }
5783 
5784 // ---------------------------------------------------------------------------
5785 
5786 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5787 {
5788  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5789  bool Present = true;
5790  THVPair TrackMapKeyPair;
5791  TTrackMapIterator TrackMapPtr;
5792 
5793  TrackMapKeyPair.first = HLoc;
5794  TrackMapKeyPair.second = VLoc;
5795  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5796  if(TrackMapPtr == TrackMap.end())
5797  {
5798  Present = false;
5799  }
5800  Utilities->CallLogPop(2057);
5801  return(Present);
5802 }
5803 
5804 // ---------------------------------------------------------------------------
5805 
5806 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5807 {
5808  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5809  AnsiString(VLoc));
5810  bool Present = true;
5811  THVPair InactiveTrackMapKeyPair;
5812  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5813 
5814  InactiveTrackMapKeyPair.first = HLoc;
5815  InactiveTrackMapKeyPair.second = VLoc;
5816  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5817  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5818  {
5819  Present = false;
5820  }
5821  Utilities->CallLogPop(2058);
5822  return(Present);
5823 }
5824 
5825 // ---------------------------------------------------------------------------
5826 
5827 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5828 // max number of elements is 2, for platforms
5829 // note that both elements of RetPair may be the same, if only one present in map
5830 {
5831  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5832  AnsiString(VLoc));
5833  THVPair InactiveTrackMapKeyPair;
5834  TIMPair RetPair;
5835  TInactiveTrackRange InactiveTrackRange;
5836 
5837  FoundFlag = false;
5838  InactiveTrackMapKeyPair.first = HLoc;
5839  InactiveTrackMapKeyPair.second = VLoc;
5840  if(InactiveTrack2MultiMap.empty())
5841  {
5842  RetPair.first = 0;
5843  RetPair.second = 0;
5844  Utilities->CallLogPop(1815);
5845  return(RetPair); // map empty
5846  }
5847  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5848  if(InactiveTrackRange.first == InactiveTrackRange.second)
5849  {
5850  RetPair.first = 0;
5851  RetPair.second = 0;
5852  Utilities->CallLogPop(514);
5853  return(RetPair); // nothing found
5854  }
5855  else
5856  {
5857  RetPair.first = InactiveTrackRange.first->second;
5858  RetPair.second = (--InactiveTrackRange.second)->second;
5859  FoundFlag = true;
5860  Utilities->CallLogPop(515);
5861  return(RetPair);
5862  }
5863 }
5864 
5865 // ---------------------------------------------------------------------------
5866 
5867 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
5868 {
5869 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5870  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5871  AnsiString(DivergingPosition));
5872  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5873  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5874  int SpeedTag1 = T1.SpeedTag;
5875  int SpeedTag2 = T2.SpeedTag;
5876 
5877  if(T1.Attribute != T2.Attribute)
5878  {
5879  Utilities->CallLogPop(516);
5880  return(false);
5881  }
5882  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5883  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5884  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5885  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5886  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5887  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
5888  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
5889  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
5890  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
5891  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
5892  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
5893  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
5894  {
5895  Utilities->CallLogPop(517);
5896  return(true);
5897  }
5898  else
5899  {
5900  Utilities->CallLogPop(518);
5901  return(false);
5902  }
5903 }
5904 
5905 // ---------------------------------------------------------------------------
5906 
5907 /*
5908  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
5909  {
5910  if(lower.second < higher.second) return true;
5911  else if(lower.second > higher.second) return false;
5912  else if(lower.second == higher.second)
5913  {
5914  if(lower.first < higher.first) return true;
5915  }
5916  return false;
5917  }
5918 */
5919 // ---------------------------------------------------------------------------
5920 
5921 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5922 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
5923 {
5924  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
5925  if(TrackElement.TrackType != GapJump)
5926  {
5927  throw Exception("Error, Wrong track type in PlotGap");
5928  }
5929  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
5930  {
5931  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
5932  }
5933  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
5934  {
5935  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
5936  }
5937  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
5938  {
5939  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
5940  }
5941  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
5942  {
5943  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
5944  }
5945  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
5946  {
5947  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
5948  }
5949  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
5950  {
5951  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
5952  }
5953  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
5954  {
5955  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
5956  }
5957  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
5958  {
5959  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
5960  }
5961  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
5962  {
5963  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
5964  }
5965  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
5966  {
5967  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
5968  }
5969  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
5970  {
5971  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
5972  }
5973  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
5974  {
5975  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
5976  }
5977  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
5978  {
5979  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
5980  }
5981  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
5982  {
5983  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
5984  }
5985  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
5986  {
5987  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
5988  }
5989  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
5990  {
5991  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
5992  }
5993  Utilities->CallLogPop(1101);
5994 }
5995 
5996 // ---------------------------------------------------------------------------
5997 
5998 void TTrack::PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp) //added for multiplayer to add overlays where coupled
5999 {
6000  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotContinuation," + TrackElement.LogTrack(1));
6001  TrackElement.PlotVariableTrackElement(7, Disp);
6002  if(!MultiplayerOverlayMap.empty()) //if it is empty then no overlays needed [map of key = THVPair, value = graphic pointer]
6003  {
6004  THVPair PosPair;
6005  PosPair.first = TrackElement.HLoc;
6006  PosPair.second = TrackElement.VLoc;
6007  TMultiplayerOverlayMap::iterator MOMIt = MultiplayerOverlayMap.find(PosPair);
6008  if(MOMIt != MultiplayerOverlayMap.end()) //if it is then no overlay is needed
6009  {
6010  Disp->PlotOutput(283, TrackElement.HLoc * 16, TrackElement.VLoc * 16, MOMIt->second);
6011  }
6012  }
6013  Utilities->CallLogPop(2403);
6014 }
6015 
6016 // ---------------------------------------------------------------------------
6017 
6018 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
6019 {
6020  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
6021  if(TrackElement.TrackType != Points)
6022  {
6023  throw Exception("Error, Wrong track type in PlotPoints");
6024  }
6025  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
6026  TrackElement.PlotVariableTrackElement(4, Disp);
6027  if(BothFillets)
6028  {
6029  if(TrackElement.SpeedTag < 28)
6030  {
6031  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
6032  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
6033  }
6034  else if(TrackElement.SpeedTag < 132)
6035  {
6036  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
6037  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
6038  }
6039  else
6040  {
6041  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
6042  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
6043  }
6044  }
6045  else
6046  {
6047  if(TrackElement.SpeedTag < 28)
6048  {
6049  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6050  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
6051  }
6052  else if(TrackElement.SpeedTag < 132)
6053  {
6054  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6055  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
6056  }
6057  else
6058  {
6059  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6060  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
6061  }
6062  }
6063 // replot platform if required
6064  TIMPair IMPair;
6065  bool FoundFlag;
6066 
6067  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6068  if(FoundFlag)
6069  {
6070  // only one platform possible at points so only need to plot IMPair.first
6071  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
6072  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
6073  }
6074  Utilities->CallLogPop(519);
6075 }
6076 
6077 // ---------------------------------------------------------------------------
6078 
6079 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6080 {
6081 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
6082  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
6083  if(TrackElement.TrackType != SignalPost)
6084  {
6085  throw Exception("Error, Wrong track type in PlotSignal");
6086  }
6087  for(int x = 0; x < 40; x++)
6088  {
6089  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
6090  {
6091  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6092  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6093 // in case existing signal is a double yellow
6094  // plot platforms if present
6095 // Graphics::TBitmap* SignalPlatformGraphic;
6096 // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
6097 // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
6098 // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
6099 // to not be plotted with the above function.
6100  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6101  // now plot signal (double yellow overwrites most of signal platform if present)
6102  // additions at version 0.6 for other aspects & ground sigs
6103  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
6104  {
6105  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
6106  }
6107  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
6108  {
6109  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
6110  }
6111  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
6112  {
6113  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6114  }
6115  else // 4 aspect
6116  {
6117  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
6118  }
6119  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
6120  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
6121  {
6122  if(TrackElement.SpeedTag == 68)
6123  {
6124  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
6125  }
6126  if(TrackElement.SpeedTag == 69)
6127  {
6128  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
6129  }
6130  if(TrackElement.SpeedTag == 70)
6131  {
6132  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
6133  }
6134  if(TrackElement.SpeedTag == 71)
6135  {
6136  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
6137  }
6138  if(TrackElement.SpeedTag == 72)
6139  {
6140  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
6141  }
6142  if(TrackElement.SpeedTag == 73)
6143  {
6144  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
6145  }
6146  if(TrackElement.SpeedTag == 74)
6147  {
6148  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
6149  }
6150  if(TrackElement.SpeedTag == 75)
6151  {
6152  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
6153  }
6154  }
6155  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
6156  // ground signal calling on, need to use normal proceed aspect
6157  {
6158  for(int x = 0; x < 40; x++)
6159  {
6160  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
6161  {
6162  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6163  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6164  // plot special signal platform if present
6165  Graphics::TBitmap* SignalPlatformGraphic;
6166  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
6167  // now plot signal
6168  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6169  }
6170  }
6171  }
6172  break;
6173  }
6174  }
6175  Utilities->CallLogPop(520);
6176 }
6177 
6178 // ---------------------------------------------------------------------------
6179 
6180 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6181 {
6182  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6183  bool FoundFlag;
6184  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6185 
6186  if(!FoundFlag)
6187  {
6188  Utilities->CallLogPop(2112);
6189  return;
6190  }
6191  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6192  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6193 
6194  // don't want 'else if' for the below as may need to plot 2 platforms
6195  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6196  {
6197  if(IAElement1.LocationName == "") // '2' will be same
6198  {
6199  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6200  }
6201  else
6202  {
6203  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6204  }
6205  }
6206  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6207  {
6208  if(IAElement1.LocationName == "") // '2' will be same
6209  {
6210  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6211  }
6212  else
6213  {
6214  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6215  }
6216  }
6217  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6218  {
6219  if(IAElement1.LocationName == "") // '2' will be same
6220  {
6221  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6222  }
6223  else
6224  {
6225  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6226  }
6227  }
6228  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6229  {
6230  if(IAElement1.LocationName == "") // '2' will be same
6231  {
6232  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6233  }
6234  else
6235  {
6236  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6237  }
6238  }
6239  Utilities->CallLogPop(2113);
6240 }
6241 
6242 // ---------------------------------------------------------------------------
6243 
6244 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6245 {
6246 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6247  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6248  AnsiString(VLoc));
6249 // find topmost LC, opening them all (to trains) in turn
6250  int UpStep = 0;
6251 
6252  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6253  {
6254  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6255  UpStep--;
6256  }
6257 // now find bottommost LC, opening them all (to trains) in turn
6258  int DownStep = 1;
6259 
6260  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6261  {
6262  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6263  DownStep++;
6264  }
6265 // find leftmost LC, opening them all (to trains) in turn
6266  int LeftStep = 0;
6267 
6268  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6269  {
6270  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6271  LeftStep--;
6272  }
6273 // now find rightmost LC, opening them all (to trains) in turn
6274  int RightStep = 1;
6275 
6276  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6277  {
6278  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6279  RightStep++;
6280  }
6281  Utilities->CallLogPop(1915);
6282 }
6283 
6284 // ---------------------------------------------------------------------------
6285 
6286 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6287 {
6288  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6289 // work upwards setting all to manual
6290  int UpStep = -1;
6291 
6292  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6293  {
6294  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6295  UpStep--;
6296  }
6297 // work downwards setting all to manual
6298  int DownStep = 1;
6299 
6300  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6301  {
6302  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6303  DownStep++;
6304  }
6305 // work leftwards setting all to manual
6306  int LeftStep = -1;
6307 
6308  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6309  {
6310  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6311  LeftStep--;
6312  }
6313 // work rightwards setting all to manual
6314  int RightStep = 1;
6315 
6316  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6317  {
6318  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6319  RightStep++;
6320  }
6321  Utilities->CallLogPop(2242);
6322 }
6323 
6324 // ---------------------------------------------------------------------------
6325 
6326 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6327 {
6328  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6329  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6330  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6331  {
6332  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6333  {
6334  BarriersDownVector.at(x).TypeOfRoute = 2;
6335  break;
6336  }
6337  }
6338  Utilities->CallLogPop(2243);
6339 }
6340 
6341 // ---------------------------------------------------------------------------
6342 
6343 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6344 {
6345  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6346 // work upwards
6347  int UpStep = 0; //start with this location
6348 
6349  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6350  {
6351  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6352  {
6353  Utilities->CallLogPop(2244);
6354  return(true);
6355  }
6356  UpStep--;
6357  }
6358 // work downwards
6359  int DownStep = 1;
6360 
6361  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6362  {
6363  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6364  {
6365  Utilities->CallLogPop(2245);
6366  return(true);
6367  }
6368  DownStep++;
6369  }
6370 // work leftwards
6371  int LeftStep = -1;
6372 
6373  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6374  {
6375  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6376  {
6377  Utilities->CallLogPop(2246);
6378  return(true);
6379  }
6380  LeftStep--;
6381  }
6382 // work rightwards
6383  int RightStep = 1;
6384 
6385  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6386  {
6387  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6388  {
6389  Utilities->CallLogPop(2247);
6390  return(true);
6391  }
6392  RightStep++;
6393  }
6394  Utilities->CallLogPop(2248);
6395  return(false);
6396 }
6397 
6398 // ---------------------------------------------------------------------------
6399 
6400 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6401 {
6402  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6403  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6404  {
6405  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6406  {
6407  BDVectorPos = x;
6408  Utilities->CallLogPop(2249);
6409  return(true);
6410  }
6411  }
6412  BDVectorPos = -1;
6413  Utilities->CallLogPop(2250);
6414  return(false);
6415 }
6416 
6417 // ---------------------------------------------------------------------------
6418 
6419 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6420 // open to trains
6421 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6422 {
6423  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6424  AnsiString(VLoc));
6425  if(!IsLCAtHV(4, HLoc, VLoc))
6426  {
6427  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6428  }
6429  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6430  {
6431  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6432  }
6433 // check for adjacent LCs & if so open (to trains)
6434  if(BaseElementSpeedTag == 1) // hor track element
6435  {
6436  // find topmost LC, opening them all (to trains) in turn
6437  int UpStep = 0;
6438  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6439  {
6440  UpStep--;
6441  }
6442  UpStep++;
6443  // now find bottommost LC, opening them all (to trains) in turn
6444  int DownStep = 1;
6445  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6446  {
6447  DownStep++;
6448  }
6449  DownStep--;
6450  // now plot graphics, UpStep is smallest & DownStep largest
6451  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6452  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6453  Graphics::TBitmap *RouteGraphic;
6454  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6455  if(TypeOfRoute == 1)
6456  {
6457  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6458  }
6459  else if(TypeOfRoute == 0)
6460  {
6461  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6462  }
6463  else //manual - no route
6464  {
6465  RouteGraphic = BaseGraphic;
6466  }
6467 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6468 // LinkSigRouteGraphicsPtr[1] ver }
6469 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6470 // LinkNonSigRouteGraphicsPtr[1] ver }
6471 
6472  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6473  {
6474  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6475  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6476  if(!Manual)
6477  {
6478  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6479  }
6480  else
6481  {
6482  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6483  }
6484  }
6485  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6486  {
6487  if(UpStep == 0)
6488  {
6489  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6490  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6491  if(!Manual)
6492  {
6493  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6494  }
6495  else
6496  {
6497  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6498  }
6499  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6500  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6501  if(!Manual)
6502  {
6503  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6504  }
6505  else
6506  {
6507  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6508  }
6509  }
6510  else
6511  {
6512  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6513  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6514  if(!Manual)
6515  {
6516  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6517  }
6518  else
6519  {
6520  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6521  }
6522  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6523  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6524  if(!Manual)
6525  {
6526  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6527  }
6528  else
6529  {
6530  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6531  }
6532  }
6533  }
6534  else // at least one plain graphic
6535  {
6536  if(UpStep == 0)
6537  {
6538  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6539  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6540  if(!Manual)
6541  {
6542  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6543  }
6544  else
6545  {
6546  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6547  }
6548  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6549  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6550  if(!Manual)
6551  {
6552  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6553  }
6554  else
6555  {
6556  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6557  }
6558  }
6559  else if(DownStep == 0)
6560  {
6561  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6562  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6563  if(!Manual)
6564  {
6565  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6566  }
6567  else
6568  {
6569  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6570  }
6571  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6572  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6573  if(!Manual)
6574  {
6575  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6576  }
6577  else
6578  {
6579  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6580  }
6581  }
6582  else
6583  {
6584  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6585  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6586  if(!Manual)
6587  {
6588  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6589  }
6590  else
6591  {
6592  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6593  }
6594  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6595  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6596  if(!Manual)
6597  {
6598  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6599  }
6600  else
6601  {
6602  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6603  }
6604  }
6605  for(int x = (UpStep + 1); x < DownStep; x++)
6606  {
6607  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6608  if(x == 0)
6609  {
6610  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6611  }
6612  else
6613  {
6614  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6615  }
6616  if(!Manual)
6617  {
6618  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6619  }
6620  else
6621  {
6622  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6623  }
6624  }
6625  }
6626  Disp->Update();
6627  Utilities->CallLogPop(1958);
6628  return;
6629  }
6630 
6631  else // ver track element
6632  {
6633  // find leftmost LC, opening them all (to trains) in turn
6634  int LStep = 0;
6635  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6636  {
6637  LStep--;
6638  }
6639  LStep++;
6640  // now find rightmost LC, opening them all (to trains) in turn
6641  int RStep = 1;
6642  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6643  {
6644  RStep++;
6645  }
6646  RStep--;
6647  // now plot graphics, LStep is smallest & RStep largest
6648  Graphics::TBitmap *RouteGraphic;
6649  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6650  if(TypeOfRoute == 1)
6651  {
6652  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6653  }
6654  else if(TypeOfRoute == 0)
6655  {
6656  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6657  }
6658  else //manual
6659  {
6660  RouteGraphic = BaseGraphic;
6661  }
6662 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6663 // LinkSigRouteGraphicsPtr[1] ver }
6664 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6665 // LinkNonSigRouteGraphicsPtr[1] ver }
6666  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6667  {
6668  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6669  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6670  if(!Manual)
6671  {
6672  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6673  }
6674  else
6675  {
6676  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6677  }
6678  }
6679  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6680  {
6681  if(LStep == 0)
6682  {
6683  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6684  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6685  if(!Manual)
6686  {
6687  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6688  }
6689  else
6690  {
6691  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6692  }
6693  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6694  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6695  if(!Manual)
6696  {
6697  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6698  }
6699  else
6700  {
6701  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6702  }
6703  }
6704  else
6705  {
6706  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6707  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6708  if(!Manual)
6709  {
6710  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6711  }
6712  else
6713  {
6714  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6715  }
6716  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6717  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6718  if(!Manual)
6719  {
6720  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6721  }
6722  else
6723  {
6724  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6725  }
6726  }
6727  }
6728  else // at least one plain graphic
6729  {
6730  if(LStep == 0)
6731  {
6732  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6733  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6734  if(!Manual)
6735  {
6736  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6737  }
6738  else
6739  {
6740  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6741  }
6742  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6743  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6744  if(!Manual)
6745  {
6746  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6747  }
6748  else
6749  {
6750  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6751  }
6752  }
6753  else if(RStep == 0)
6754  {
6755  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6756  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6757  if(!Manual)
6758  {
6759  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6760  }
6761  else
6762  {
6763  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6764  }
6765  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6766  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6767  if(!Manual)
6768  {
6769  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6770  }
6771  else
6772  {
6773  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6774  }
6775  }
6776  else
6777  {
6778  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6779  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6780  if(!Manual)
6781  {
6782  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6783  }
6784  else
6785  {
6786  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6787  }
6788  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6789  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6790  if(!Manual)
6791  {
6792  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6793  }
6794  else
6795  {
6796  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6797  }
6798  }
6799  for(int x = (LStep + 1); x < RStep; x++)
6800  {
6801  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6802  if(x == 0)
6803  {
6804  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
6805  }
6806  else
6807  {
6808  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
6809  }
6810  if(!Manual)
6811  {
6812  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6813  }
6814  else
6815  {
6816  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6817  }
6818  }
6819  }
6820  Disp->Update();
6821  Utilities->CallLogPop(1896);
6822  return;
6823  }
6824 }
6825 
6826 // ---------------------------------------------------------------------------
6827 
6828 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
6829 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6830 {
6831  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
6832  AnsiString(HLoc) + "," + AnsiString(VLoc));
6833  if(!IsLCAtHV(29, HLoc, VLoc))
6834  {
6835  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6836  }
6837  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6838  {
6839  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6840  }
6841 // check for adjacent LCs & if so open (to trains)
6842  if(BaseElementSpeedTag == 1) // hor track element
6843  {
6844  // find topmost LC, opening them all (to trains) in turn
6845  int UpStep = 0;
6846  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6847  {
6848  UpStep--;
6849  }
6850  UpStep++;
6851  // now find bottommost LC, opening them all (to trains) in turn
6852  int DownStep = 1;
6853  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
6854  {
6855  DownStep++;
6856  }
6857  DownStep--;
6858  // now plot graphics, UpStep is smallest & DownStep largest
6859  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6860  {
6861  if(!Manual)
6862  {
6863  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6864  }
6865  else
6866  {
6867  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6868  }
6869  }
6870  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6871  {
6872  if(!Manual)
6873  {
6874  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6875  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6876  }
6877  else
6878  {
6879  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6880  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6881  }
6882  }
6883  else // at least one plain graphic
6884  {
6885  if(!Manual)
6886  {
6887  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6888  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6889  for(int x = (UpStep + 1); x < DownStep; x++)
6890  {
6891  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6892  }
6893  }
6894  else
6895  {
6896  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6897  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6898  for(int x = (UpStep + 1); x < DownStep; x++)
6899  {
6900  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6901  }
6902  }
6903  }
6904  // set markers
6905  for(int x = UpStep; x <= DownStep; x++)
6906  {
6907  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6908  }
6909  Display->Update();
6910  Utilities->CallLogPop(1944);
6911  return;
6912  }
6913 
6914  else // ver track element
6915  {
6916  // find leftmost LC, opening them all (to trains) in turn
6917  int LStep = 0;
6918  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
6919  {
6920  LStep--;
6921  }
6922  LStep++;
6923  // now find rightmost LC, opening them all (to trains) in turn
6924  int RStep = 1;
6925  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
6926  {
6927  RStep++;
6928  }
6929  RStep--;
6930  // now plot graphics, LStep is smallest & RStep largest
6931  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6932  {
6933  if(!Manual)
6934  {
6935  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6936  }
6937  else
6938  {
6939  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6940  }
6941  }
6942  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6943  {
6944  if(!Manual)
6945  {
6946  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6947  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6948  }
6949  else
6950  {
6951  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6952  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6953  }
6954  }
6955  else // at least one plain graphic
6956  {
6957  if(!Manual)
6958  {
6959  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6960  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6961  for(int x = (LStep + 1); x < RStep; x++)
6962  {
6963  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6964  }
6965  }
6966  else
6967  {
6968  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6969  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6970  for(int x = (LStep + 1); x < RStep; x++)
6971  {
6972  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6973  }
6974  }
6975  }
6976  // set markers
6977  for(int x = LStep; x <= RStep; x++)
6978  {
6979  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
6980  }
6981  Disp->Update();
6982  Utilities->CallLogPop(1945);
6983  return;
6984  }
6985 }
6986 
6987 // ---------------------------------------------------------------------------
6988 
6989 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
6990 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6991 {
6992  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6993  AnsiString(VLoc));
6994  if(!IsLCAtHV(9, HLoc, VLoc))
6995  {
6996  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
6997  }
6998  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6999  {
7000  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
7001  }
7002 // check for adjacent LCs & if so close (to trains)
7003  if(BaseElementSpeedTag == 1) // hor track element
7004  {
7005  // find topmost LC, closing them all (to trains) in turn
7006  int UpStep = 0;
7007  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7008  {
7009  UpStep--;
7010  }
7011  UpStep++;
7012  // now find bottommost LC, opening them all (to trains) in turn
7013  int DownStep = 1;
7014  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
7015  {
7016  DownStep++;
7017  }
7018  DownStep--;
7019  // now plot graphics, UpStep is smallest & DownStep largest
7020  for(int x = UpStep; x < (DownStep + 1); x++)
7021  {
7022  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
7023  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
7024  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7025  }
7026  Disp->Update();
7027  Utilities->CallLogPop(1959);
7028  return;
7029  }
7030 
7031  else // ver track element
7032  {
7033  // find leftmost LC, closing them all (to trains) in turn
7034  int LStep = 0;
7035  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
7036  {
7037  LStep--;
7038  }
7039  LStep++;
7040  // now find rightmost LC, opening them all (to trains) in turn
7041  int RStep = 1;
7042  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
7043  {
7044  RStep++;
7045  }
7046  RStep--;
7047  // now plot graphics, LStep is smallest & RStep largest
7048  for(int x = LStep; x < (RStep + 1); x++)
7049  {
7050  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7051  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
7052  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7053  }
7054  Disp->Update();
7055  Utilities->CallLogPop(1960);
7056  return;
7057  }
7058 }
7059 
7060 // ---------------------------------------------------------------------------
7061 
7062 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
7063 // closed to trains
7064 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7065 {
7066  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
7067  AnsiString(HLoc) + "," + AnsiString(VLoc));
7068  if(!IsLCAtHV(34, HLoc, VLoc))
7069  {
7070  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7071  }
7072  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7073  {
7074  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7075  }
7076  TTrackElement TE;
7077 
7078 // check for adjacent LCs & if so close (to trains)
7079  if(BaseElementSpeedTag == 1) // hor track element
7080  {
7081  // find topmost LC, closing them all (to trains) in turn
7082  int UpStep = 0;
7083  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7084  {
7085  UpStep--;
7086  }
7087  UpStep++;
7088  // now find bottommost LC, opening them all (to trains) in turn
7089  int DownStep = 1;
7090  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
7091  {
7092  DownStep++;
7093  }
7094  DownStep--;
7095  // now plot graphics, UpStep is smallest & DownStep largest
7096  for(int x = UpStep; x <= DownStep; x++)
7097  {
7098  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7099  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7100  }
7101  Display->Update();
7102  Utilities->CallLogPop(1946);
7103  return;
7104  }
7105 
7106  else // ver track element
7107  {
7108  // find leftmost LC, closing them all (to trains) in turn
7109  int LStep = 0;
7110  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
7111  {
7112  LStep--;
7113  }
7114  LStep++;
7115  // now find rightmost LC, opening them all (to trains) in turn
7116  int RStep = 1;
7117  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
7118  {
7119  RStep++;
7120  }
7121  RStep--;
7122  // now plot graphics, LStep is smallest & RStep largest
7123  for(int x = LStep; x <= RStep; x++)
7124  {
7125  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7126  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
7127  }
7128  Display->Update();
7129  Utilities->CallLogPop(1947);
7130  return;
7131  }
7132 }
7133 
7134 // ---------------------------------------------------------------------------
7135 
7136 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
7137 {
7138  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7139  Graphics::TBitmap *RouteGraphic;
7140  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
7141 
7142  if(BaseElementSpeedTag == 1)
7143  {
7144  if(TypeOfRoute == 1)
7145  {
7146  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
7147  }
7148  else if(TypeOfRoute == 0)
7149  {
7150  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
7151  }
7152  else //manual
7153  {
7154  RouteGraphic = BaseGraphic;
7155  }
7156  if(State == Raising)
7157  {
7158  RouteGraphic = BaseGraphic;
7159  }
7160  }
7161  else
7162  {
7163  BaseGraphic = RailGraphics->gl2;
7164  if(TypeOfRoute == 1)
7165  {
7166  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
7167  }
7168  else if(TypeOfRoute == 0)
7169  {
7170  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7171  }
7172  else
7173  {
7174  RouteGraphic = BaseGraphic; //manual
7175  }
7176  if(State == Raising)
7177  {
7178  RouteGraphic = BaseGraphic;
7179  }
7180  }
7181  int UpStep = 0;
7182 
7183  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7184  {
7185  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7186  if(UpStep == 0)
7187  {
7188  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7189  }
7190  else
7191  {
7192  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7193  }
7194  UpStep--;
7195  }
7196 // now find bottommost LC, opening them all (to trains) in turn
7197  int DownStep = 1;
7198 
7199  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7200  {
7201  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7202  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7203  DownStep++;
7204  }
7205  int LeftStep = 0;
7206 
7207  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7208  {
7209  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7210  if(LeftStep == 0)
7211  {
7212  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7213  }
7214  else
7215  {
7216  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7217  }
7218  LeftStep--;
7219  }
7220 // now find rightmost LC, opening them all (to trains) in turn
7221  int RightStep = 1;
7222 
7223  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7224  {
7225  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7226  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7227  RightStep++;
7228  }
7229  Disp->Update();
7230  Utilities->CallLogPop(1914);
7231 }
7232 
7233 // ---------------------------------------------------------------------------
7234 
7235 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7236 {
7237 // return false for no LC there, flashing or a closed (to trains) LC
7238  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7239  bool FoundFlag;
7240  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7241 
7242  if(!FoundFlag)
7243  {
7244  Utilities->CallLogPop(1898);
7245  return(false);
7246  }
7247  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7248  {
7249  Utilities->CallLogPop(1899);
7250  return(false);
7251  }
7252  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7253  {
7254  Utilities->CallLogPop(1900);
7255  return(true);
7256  }
7257  Utilities->CallLogPop(1901);
7258  return(false);
7259 }
7260 
7261 // ---------------------------------------------------------------------------
7262 
7263 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7264 {
7265 // return false for no LC there, flashing LC or open (to trains) LC
7266  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7267  bool FoundFlag;
7268  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7269 
7270  if(!FoundFlag)
7271  {
7272  Utilities->CallLogPop(1922);
7273  return(false);
7274  }
7275  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7276  {
7277  Utilities->CallLogPop(1923);
7278  return(false);
7279  }
7280  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7281  {
7282  Utilities->CallLogPop(1924);
7283  return(true);
7284  }
7285  Utilities->CallLogPop(1925);
7286  return(false);
7287 }
7288 
7289 // ---------------------------------------------------------------------------
7290 
7291 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7292 {
7293 // return true for barrier in process of moving
7294  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7295  bool FoundFlag;
7296  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7297 
7298  if(!FoundFlag)
7299  {
7300  Utilities->CallLogPop(1918);
7301  return(false);
7302  }
7303  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7304  {
7305  Utilities->CallLogPop(1919);
7306  return(false);
7307  }
7308  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7309  {
7310  Utilities->CallLogPop(1920);
7311  return(true);
7312  }
7313  Utilities->CallLogPop(1921);
7314  return(false);
7315 }
7316 
7317 // ---------------------------------------------------------------------------
7318 
7319 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7320 {
7321 // return true for an LC at H&V
7322  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7323  bool FoundFlag;
7324  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7325 
7326  if(!FoundFlag)
7327  {
7328  Utilities->CallLogPop(1902);
7329  return(false);
7330  }
7331  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7332  {
7333  Utilities->CallLogPop(1903);
7334  return(false);
7335  }
7336  Utilities->CallLogPop(1904);
7337  return(true);
7338 }
7339 
7340 // ---------------------------------------------------------------------------
7341 
7342 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7343 {
7344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7345  AnsiString(Attr));
7346  bool FoundFlag;
7347  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7348 
7349  if(!FoundFlag)
7350  {
7351  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7352  }
7353  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7354  {
7355  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7356  }
7357  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7358  Utilities->CallLogPop(1905);
7359  return;
7360 }
7361 
7362 // ---------------------------------------------------------------------------
7363 
7365 {
7366  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7367  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7368  {
7369  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7370  if(InactiveTrackElement.TrackType == LevelCrossing)
7371  {
7372  InactiveTrackElementAt(141, x).Attribute = 0;
7373  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7374  }
7375  }
7376  Utilities->CallLogPop(1913);
7377  return;
7378 }
7379 
7380 // ---------------------------------------------------------------------------
7381 
7382 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7383 {
7384 // return true if there is either a route set or being set on any element or a train on any element
7385  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7386  "," + AnsiString(VLoc));
7387 
7388  THVPair TrackMapKeyPair;
7389  TTrack::TTrackMapIterator TrackMapPtr;
7390  int DummyRouteNumber;
7391 
7392  TrainPresent = false;
7393 // find topmost LC, checking each for routes & trains
7394  int UpStep = 0;
7395 
7396  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7397  {
7398  TrackMapKeyPair.first = HLoc;
7399  TrackMapKeyPair.second = VLoc + UpStep;
7400  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7401  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7402  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7403  {
7404  Utilities->CallLogPop(1932);
7405  return(true);
7406  }
7407  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7408  {
7409  TrainPresent = true;
7410  Utilities->CallLogPop(1933);
7411  return(true);
7412  }
7413  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7414  {
7415  Utilities->CallLogPop(2274);
7416  return(true);
7417  }
7418  UpStep--;
7419  }
7420 // now find bottommost LC, opening them all (to trains) in turn
7421  int DownStep = 1;
7422 
7423  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7424  {
7425  TrackMapKeyPair.first = HLoc;
7426  TrackMapKeyPair.second = VLoc + DownStep;
7427  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7428  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7429  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7430  {
7431  Utilities->CallLogPop(1934);
7432  return(true);
7433  }
7434  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7435  {
7436  TrainPresent = true;
7437  Utilities->CallLogPop(1935);
7438  return(true);
7439  }
7440  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7441  {
7442  Utilities->CallLogPop(2275);
7443  return(true);
7444  }
7445  DownStep++;
7446  }
7447 // find leftmost LC
7448  int LeftStep = 0;
7449 
7450  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7451  {
7452  TrackMapKeyPair.first = HLoc + LeftStep;
7453  TrackMapKeyPair.second = VLoc;
7454  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7455  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7456  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7457  {
7458  Utilities->CallLogPop(1936);
7459  return(true);
7460  }
7461  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7462  {
7463  TrainPresent = true;
7464  Utilities->CallLogPop(1937);
7465  return(true);
7466  }
7467  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7468  {
7469  Utilities->CallLogPop(2276);
7470  return(true);
7471  }
7472  LeftStep--;
7473  }
7474 // now find rightmost LC, opening them all (to trains) in turn
7475  int RightStep = 1;
7476 
7477  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7478  {
7479  TrackMapKeyPair.first = HLoc + RightStep;
7480  TrackMapKeyPair.second = VLoc;
7481  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7482  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7483  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7484  {
7485  Utilities->CallLogPop(1938);
7486  return(true);
7487  }
7488  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7489  {
7490  TrainPresent = true;
7491  Utilities->CallLogPop(1939);
7492  return(true);
7493  }
7494  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7495  {
7496  Utilities->CallLogPop(2277);
7497  return(true);
7498  }
7499  RightStep++;
7500  }
7501  Utilities->CallLogPop(1940);
7502  return(false);
7503 }
7504 
7505 // ---------------------------------------------------------------------------
7506 
7507 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7508 {
7509  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7510  for(unsigned int x = 0; x < SearchVector.size(); x++)
7511  {
7512  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7513  {
7514  Utilities->CallLogPop(2278);
7515  return(true);
7516  }
7517  }
7518  Utilities->CallLogPop(2279);
7519  return(false);
7520 }
7521 
7522 // ---------------------------------------------------------------------------
7523 
7524 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7525 {
7526  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7527  AnsiString(HLoc) + "," + AnsiString(VLoc));
7528  if(!IsLCAtHV(60, HLoc, VLoc))
7529  {
7530  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7531  }
7532 
7533 // check for adjacent LCs
7534  // find topmost LC
7535  int UpStep = 0;
7536  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7537  {
7538  UpStep--;
7539  }
7540  UpStep++;
7541  // now find bottommost LC, opening them all (to trains) in turn
7542  int DownStep = 1;
7543  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7544  {
7545  DownStep++;
7546  }
7547  DownStep--;
7548  // now plot graphics, UpStep is smallest & DownStep largest
7549  for(int x = UpStep; x <= DownStep; x++)
7550  {
7551  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7552  }
7553 
7554  // find leftmost LC, closing them all (to trains) in turn
7555  int LStep = 0;
7556  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7557  {
7558  LStep--;
7559  }
7560  LStep++;
7561  // now find rightmost LC, opening them all (to trains) in turn
7562  int RStep = 1;
7563  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7564  {
7565  RStep++;
7566  }
7567  RStep--;
7568  // now plot graphics, LStep is smallest & RStep largest
7569  for(int x = LStep; x <= RStep; x++)
7570  {
7571  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7572  }
7573  Display->Update();
7574  Utilities->CallLogPop(2315);
7575  return;
7576 }
7577 
7578 // ---------------------------------------------------------------------------
7579 
7580 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7581 {
7582  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7583  if(TrackElement.TrackType != Points)
7584  {
7585  throw Exception("Error, Wrong track type in GetFilletGraphic");
7586  }
7587  if(TrackElement.SpeedTag < 28)
7588  {
7589  Utilities->CallLogPop(521);
7590  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7591  }
7592  else if(TrackElement.SpeedTag < 132)
7593  {
7594  Utilities->CallLogPop(522);
7595 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7596  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7597  }
7598  else
7599  {
7600  Utilities->CallLogPop(1537);
7601  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7602  }
7603 }
7604 
7605 // ---------------------------------------------------------------------------
7606 
7608 {
7609  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDElements");
7610  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7611  {
7612  TrackElementAt(1351, x).TrainIDOnElement = -1;
7615  }
7616  Utilities->CallLogPop(1342);
7617 }
7618 
7619 // ---------------------------------------------------------------------------
7620 
7621 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7622 /*
7623  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7624 */
7625 {
7626  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7627  AnsiString(ScreenPosV));
7628  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7629  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7630 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7631  Utilities->CallLogPop(535);
7632 }
7633 
7634 // ---------------------------------------------------------------------------
7635 
7636 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7637 /*
7638  Converts the screen position to the true (without offsets) position
7639 */
7640 {
7641  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7642  AnsiString(ScreenPosV));
7643  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7644  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7645  Utilities->CallLogPop(536);
7646 }
7647 
7648 // ---------------------------------------------------------------------------
7649 
7650 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7651 {
7652  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7653  AnsiString(VPosTrue));
7654  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7655  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7656  Utilities->CallLogPop(537);
7657 }
7658 
7659 // ---------------------------------------------------------------------------
7660 
7661 void TTrack::CheckMapAndTrack(int Caller) // test
7662 {
7663  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7664  int Zeroes = 0;
7665  bool FoundFlag;
7666 
7667  for(unsigned int a = 0; a < TrackVector.size(); a++)
7668  {
7669  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
7670  if(CheckElement.SpeedTag == 0)
7671  {
7672  Zeroes++; // zeroed elements not saved in map
7673  }
7674  else
7675  {
7676  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7677  if(!FoundFlag)
7678  {
7679  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7680  " in TrackMap, Caller=" + (AnsiString)Caller);
7681  }
7682  if(MapVecPos != (int)a)
7683  {
7684  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7685  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7686  (AnsiString)Caller);
7687  }
7688  }
7689  }
7690  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7691  {
7692  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7693  " Caller=" + (AnsiString)Caller);
7694  }
7695  Utilities->CallLogPop(538);
7696  return;
7697 }
7698 
7699 // ---------------------------------------------------------------------------
7700 
7701 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7702 {
7703  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7704  bool FoundFlag;
7705  TIMPair InactivePair;
7706 
7707  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7708  {
7709  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
7710  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7711  if(!FoundFlag)
7712  {
7713  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7714  " in InactiveMap, Caller=" + (AnsiString)Caller);
7715  }
7716  if((InactivePair.first != a) && (InactivePair.second != a))
7717  {
7718  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7719  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7720  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7721  }
7722  }
7723  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
7724  {
7725  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7726  " Caller=" + (AnsiString)Caller);
7727  }
7728  Utilities->CallLogPop(539);
7729 }
7730 
7731 // ---------------------------------------------------------------------------
7732 
7733 void TTrack::CheckGapMap(int Caller) // test
7734 {
7735  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
7736  int Position1, Position2;
7737  TTrackElement TrackElement1, TrackElement2;
7738  TGapMapIterator GapMapPtr;
7739 
7740  if(!GapMap.empty())
7741  {
7742  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
7743  {
7744  int HLoc1 = GapMapPtr->first.first;
7745  int VLoc1 = GapMapPtr->first.second;
7746  int HLoc2 = GapMapPtr->second.first;
7747  int VLoc2 = GapMapPtr->second.second;
7748  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
7749  {
7750  throw Exception("Failed to find H & V for gap1, GapMap in error");
7751  }
7752  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
7753  {
7754  throw Exception("Failed to find H & V for gap2, GapMap in error");
7755  }
7756  if(TrackElementAt(17, Position1).TrackType != GapJump)
7757  {
7758  throw Exception("Element at Pos1 not a gap, GapMap in error");
7759  }
7760  if(TrackElementAt(18, Position2).TrackType != GapJump)
7761  {
7762  throw Exception("Element at Pos2 not a gap, GapMap in error");
7763  }
7764  }
7765  }
7766  unsigned int GapCount = 0;
7767 
7768  for(unsigned int a = 0; a < TrackVector.size(); a++)
7769  {
7770  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
7771  if(CheckElement.TrackType == GapJump)
7772  {
7773  GapCount++;
7774  }
7775  }
7776  if((GapMap.size() * 2) != GapCount)
7777  {
7778  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7779  (AnsiString)Caller);
7780  }
7781  Utilities->CallLogPop(540);
7782 }
7783 
7784 // ---------------------------------------------------------------------------
7785 
7786 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7787 {
7788  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7789  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7790  {
7791  if(TrackFinished)
7792  {
7793  throw Exception("Error - TrackFinished with erase element still present");
7794  }
7795  Utilities->CallLogPop(541);
7796  return; // erased element, can't set ID
7797  }
7798  AnsiString IDString;
7799 
7800  if(TrackElement.HLoc < 0)
7801  {
7802  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
7803  }
7804  else
7805  {
7806  IDString = AnsiString(TrackElement.HLoc) + "-";
7807  }
7808  if(TrackElement.VLoc < 0)
7809  {
7810  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
7811  }
7812  else
7813  {
7814  IDString += AnsiString(TrackElement.VLoc);
7815  }
7816  TrackElement.ElementID = IDString;
7817  Utilities->CallLogPop(542);
7818 }
7819 
7820 // ---------------------------------------------------------------------------
7821 
7822 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
7823 {
7824 // e.g. "8-13", "00008-13", "N43-N127", etc
7825  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString," + String); //String was inside " marks, corrected at v2.13.0
7826  int DelimPos;
7827 try //try..catch added at v2.13.0 following Amon Sadler's error file received on 24/03/22, had N-113-5 rather than N113-5
7828  {
7829  for(int x = 1; x < String.Length() + 1; x++)
7830  {
7831  if(String.IsDelimiter("-", x))
7832  {
7833  DelimPos = x;
7834  break;
7835  }
7836  if(x == String.Length())
7837  {
7838  if(GiveMessages)
7839  {
7840  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
7841  }
7842  Utilities->CallLogPop(543);
7843  return(-1);
7844  }
7845  }
7846  if(DelimPos == 1)
7847  {
7848  if(GiveMessages)
7849  {
7850  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
7851  }
7852  Utilities->CallLogPop(544);
7853  return(-1);
7854  }
7855  if(DelimPos == String.Length())
7856  {
7857  if(GiveMessages)
7858  {
7859  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
7860  }
7861  Utilities->CallLogPop(545);
7862  return(-1);
7863  }
7864  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
7865  {
7866  if(GiveMessages)
7867  {
7868  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
7869  }
7870  Utilities->CallLogPop(1508);
7871  return(-1);
7872  }
7873  int HLoc, VLoc;
7874 
7875  if(String.SubString(1, 1) != "N")
7876  {
7877  for(int x = 1; x < DelimPos; x++)
7878  {
7879  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7880  {
7881  if(GiveMessages)
7882  {
7883  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7884  }
7885  Utilities->CallLogPop(546);
7886  return(-1);
7887  }
7888  }
7889  }
7890  if(String.SubString(1, 1) == "N")
7891  {
7892  for(int x = 2; x < DelimPos; x++)
7893  {
7894  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7895  {
7896  if(GiveMessages)
7897  {
7898  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7899  }
7900  Utilities->CallLogPop(763);
7901  return(-1);
7902  }
7903  }
7904  }
7905  if(String.SubString(1, 1) == "N")
7906  {
7907  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
7908  }
7909  else
7910  {
7911  HLoc = String.SubString(1, DelimPos - 1).ToInt();
7912  }
7913  if(String.SubString(DelimPos + 1, 1) != "N")
7914  {
7915  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
7916  {
7917  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7918  {
7919  if(GiveMessages)
7920  {
7921  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7922  }
7923  Utilities->CallLogPop(547);
7924  return(-1);
7925  }
7926  }
7927  }
7928  if(String.SubString(DelimPos + 1, 1) == "N")
7929  {
7930  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
7931  {
7932  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7933  {
7934  if(GiveMessages)
7935  {
7936  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7937  }
7938  Utilities->CallLogPop(764);
7939  return(-1);
7940  }
7941  }
7942  }
7943  if(String.SubString(DelimPos + 1, 1) == "N")
7944  {
7945  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
7946  }
7947  else
7948  {
7949  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
7950  }
7951  THVPair HVPair(HLoc, VLoc);
7952  TTrackMapIterator TrackMapPtr;
7953 
7954  TrackMapPtr = TrackMap.find(HVPair);
7955  if(TrackMapPtr == TrackMap.end())
7956  {
7957  if(GiveMessages)
7958  {
7959  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
7960  }
7961  Utilities->CallLogPop(548);
7962  return(-1);
7963  }
7964  Utilities->CallLogPop(549);
7965  return(TrackMapPtr->second);
7966  }
7967  catch(const Exception &e) //non-error catch - catches any errors not already caught above
7968  //(added at v2.13.0 following Amon Sadler's error file received on 24/03/22), had N-113-5 rather than N113-5
7969  {
7970  ShowMessage("Syntax error in track element identifier: <" + String + ">");
7971  Utilities->CallLogPop(2481);
7972  return(-1);
7973  }
7974 }
7975 
7976 // ---------------------------------------------------------------------------
7977 
7978 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
7979 /*
7980  True for linked properly at both ends
7981 */
7982 {
7983  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
7984  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
7985  int HLoc = TrackElement.HLoc;
7986  int VLoc = TrackElement.VLoc;
7987 
7988  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
7989  {
7990  Utilities->CallLogPop(1821);
7991  return(false);
7992  }
7993  if(TrackElement.SpeedTag == 129) // vertical footbridge
7994  {
7995  // check top connection
7996  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
7997  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
7998  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
7999  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
8000  {
8001  Utilities->CallLogPop(550);
8002  return(false);
8003  }
8004  // check bottom connection
8005  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
8006  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
8007  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
8008  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
8009  {
8010  Utilities->CallLogPop(551);
8011  return(false);
8012  }
8013  }
8014  if(TrackElement.SpeedTag == 145) // vertical underpass
8015  {
8016  // check top connection
8017  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
8018  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
8019  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
8020  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
8021  {
8022  Utilities->CallLogPop(2114);
8023  return(false);
8024  }
8025  // check bottom connection
8026  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
8027  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
8028  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
8029  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
8030  {
8031  Utilities->CallLogPop(2115);
8032  return(false);
8033  }
8034  }
8035  if(TrackElement.SpeedTag == 130) // hor footbridge
8036  {
8037  // check left connection
8038  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
8039  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
8040  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
8041  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
8042  {
8043  Utilities->CallLogPop(552);
8044  return(false);
8045  }
8046  // check right connection
8047  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
8048  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
8049  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
8050  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
8051  {
8052  Utilities->CallLogPop(553);
8053  return(false);
8054  }
8055  }
8056  if(TrackElement.SpeedTag == 146) // hor u'pass
8057  {
8058  // check left connection
8059  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
8060  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
8061  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
8062  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
8063  {
8064  Utilities->CallLogPop(2116);
8065  return(false);
8066  }
8067  // check right connection
8068  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
8069  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
8070  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
8071  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
8072  {
8073  Utilities->CallLogPop(2117);
8074  return(false);
8075  }
8076  }
8077  Utilities->CallLogPop(554);
8078  return(true);
8079 }
8080 
8081 // ---------------------------------------------------------------------------
8082 
8083 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8084 /*
8085  return true if the SpeedTag present in the map at H & V
8086 */
8087 {
8088  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8089  AnsiString(SpeedTag));
8090  if(InactiveTrack2MultiMap.empty())
8091  {
8092  Utilities->CallLogPop(555);
8093  return(false);
8094  }
8095  THVPair HVPair(HLoc, VLoc);
8097  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
8098  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
8099 
8100  if(HVRange.first == HVRange.second)
8101  {
8102  Utilities->CallLogPop(556);
8103  return(false);
8104  }
8105  else
8106  {
8107  HVIt1 = HVRange.first;
8108  }
8109  TTrackElement Temp1, Temp2; // test
8110 
8111  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
8112  if(--HVRange.second != HVRange.first)
8113  {
8114  HVIt2 = HVRange.second;
8115  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
8116  }
8117  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
8118  HVIt2->second).SpeedTag == SpeedTag)))
8119  {
8120  Utilities->CallLogPop(557);
8121  return(true);
8122  }
8123  else
8124  {
8125  Utilities->CallLogPop(558);
8126  return(false);
8127  }
8128 }
8129 
8130 // ---------------------------------------------------------------------------
8131 
8132 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8133 /*
8134  return true if the SpeedTag present in the map at H & V
8135 */
8136 {
8137  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8138  AnsiString(SpeedTag));
8139  if(TrackMap.empty())
8140  {
8141  Utilities->CallLogPop(559);
8142  return(false);
8143  }
8144  THVPair HVPair(HLoc, VLoc);
8145  TTrackMapIterator End = TrackMap.end();
8146  TTrackMapIterator It = End;
8147 
8148  It = TrackMap.find(HVPair);
8149  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
8150  {
8151  Utilities->CallLogPop(560);
8152  return(true);
8153  }
8154  else
8155  {
8156  Utilities->CallLogPop(561);
8157  return(false);
8158  }
8159 }
8160 
8161 // ---------------------------------------------------------------------------
8162 
8163 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
8164 {
8165 /*
8166  General:
8167  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
8168  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
8169  a NamedNonStationLocation.
8170  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
8171  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
8172  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
8173  platform at that location).
8174 
8175  Linked named location elements are those explained in TTrack::TTrack()
8176 
8177  Detail:
8178  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
8179  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
8180  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
8181  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
8182  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8183  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8184 
8185  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8186  this function a single element should be in the List (normally from the user's selection but can also be from
8187  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8188  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8189  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8190  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8191  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8192  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8193  moves them into the Map. At the end all linked elements are in the Map.
8194 
8195  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8196  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8197  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8198 */
8199 
8200 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8201 // Display->FileDiagnostics(TestString);//test
8202 
8203  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8204  AnsiString TestString1, TestString2; // test
8205 
8206  Track->LNDone2MultiMap.clear();
8207  if(LNPendingList.size() != 1)
8208  {
8209  throw Exception("LNPendingList size not 1 on entry");
8210  }
8211  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8212  while(!LNPendingList.empty())
8213  {
8214  CurrentElementNumber = LNPendingList.front();
8215  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8216  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8217  int H = CurrentElement->HLoc;
8218  int V = CurrentElement->VLoc;
8219  int Tag = CurrentElement->SpeedTag;
8220  if(Tag == 76) // top plat
8221  {
8222  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8223  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8224  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8225  for(int x = 0; x < 25; x++)
8226  {
8227  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8228  {
8229  LNPendingList.insert(LNPendingList.end(), NewElement);
8230  }
8231  }
8232  }
8233  else if(Tag == 77) // bot plat
8234  {
8235  for(int x = 0; x < 25; x++)
8236  {
8237  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8238  {
8239  LNPendingList.insert(LNPendingList.end(), NewElement);
8240  }
8241  }
8242  }
8243  else if(Tag == 78) // l plat
8244  {
8245  for(int x = 0; x < 25; x++)
8246  {
8247  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8248  {
8249  LNPendingList.insert(LNPendingList.end(), NewElement);
8250  }
8251  }
8252  }
8253  else if(Tag == 79) // r plat
8254  {
8255  for(int x = 0; x < 25; x++)
8256  {
8257  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8258  {
8259  LNPendingList.insert(LNPendingList.end(), NewElement);
8260  }
8261  }
8262  }
8263  else if(Tag == 96) // conc
8264  {
8265  for(int x = 0; x < 28; x++)
8266  {
8267  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8268  {
8269  LNPendingList.insert(LNPendingList.end(), NewElement);
8270  }
8271  }
8272  }
8273  else if(Tag == 129) // vert footbridge
8274  {
8275  for(int x = 0; x < 8; x++)
8276  {
8277  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8278  {
8279  LNPendingList.insert(LNPendingList.end(), NewElement);
8280  }
8281  }
8282  }
8283  else if(Tag == 130) // hor footbridge
8284  {
8285  for(int x = 0; x < 8; x++)
8286  {
8287  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8288  {
8289  LNPendingList.insert(LNPendingList.end(), NewElement);
8290  }
8291  }
8292  }
8293  else if(Tag == 131) // named location
8294  {
8295  for(int x = 0; x < 4; x++)
8296  {
8297  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8298  {
8299  LNPendingList.insert(LNPendingList.end(), NewElement);
8300  }
8301  }
8302  }
8303  else if(Tag == 145) // v u'pass
8304  {
8305  for(int x = 0; x < 8; x++)
8306  {
8307  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8308  {
8309  LNPendingList.insert(LNPendingList.end(), NewElement);
8310  }
8311  }
8312  }
8313  else if(Tag == 146) // h u'pass
8314  {
8315  for(int x = 0; x < 8; x++)
8316  {
8317  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8318  {
8319  LNPendingList.insert(LNPendingList.end(), NewElement);
8320  }
8321  }
8322  }
8323  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8324 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8325  if(AddingElements)
8326  {
8327  int HPos, VPos; // not used but needed for FindText function
8328  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8329  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8330  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8331  {
8332  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8333  if((ExistingName != "") && (ExistingName != LocationName))
8334  {
8335  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8336  {
8337  } // name not in LocationNameMultiMap, so don't erase from TextVector
8338  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8339  {
8340  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8341  {
8342  ;
8343  } // condition not used
8344 
8345  }
8346  }
8347  }
8348  }
8349  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8350  // track at that loc
8351  THVPair HVPair(H, V);
8352  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8353  LNDone2MultiMapEntry.first = HVPair;
8354  LNDone2MultiMapEntry.second = LNPendingList.front();
8355  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8356  LNPendingList.erase(LNPendingList.begin());
8357  }
8358 
8359 // search all name multimap for same name where corresponding active elements don't appear in
8360 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8361 
8362  TLocationNameMultiMapIterator SNIterator;
8363  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8364  bool FoundFlag, ErasedFlag = false;
8365 
8366  if(SNRange.first != SNRange.second)
8367  {
8368  SNRange.first--; // now pointing to before the first
8369  SNRange.second--; // now pointing to the last
8370  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8371  {
8372  // Same elements are in Done map as in name map
8373  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8374  {
8375  ErasedFlag = true;
8376  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8377  TVIt->LocationName = "";
8378  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8379  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8380  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8381  {
8382  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8383  if(FoundFlag)
8384  {
8385  TrackElementAt(20, Position).LocationName = "";
8386  TrackElementAt(21, Position).ActiveTrackElementName = "";
8387  }
8388  }
8389  // erase name in name map
8390 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8391  }
8392  }
8393  }
8394  if(ErasedFlag)
8395  {
8397  }
8398  if(TrackFinished)
8399  {
8401  }
8402 // set here as well as in LinkTrack so don't have to link track just because a name added
8403 // if track not finished then will be set when track validated
8404 
8405 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8406 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8407 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8408 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8409 // so the error would be seen.
8410 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8411  std::pair<AnsiString, char>TempMapPair;
8412 
8413  ContinuationNameMap.clear();
8414  for(int x = 0; x < Track->TrackVectorSize(); x++)
8415  {
8416  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8417  {
8418  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8419  TempMapPair.second = 'x'; // unused
8420  ContinuationNameMap.insert(TempMapPair);
8421  }
8422  }
8423 //end of addition
8424  CheckLocationNameMultiMap(1); // test
8425  Utilities->CallLogPop(562);
8426 }
8427 
8428 // ---------------------------------------------------------------------------
8429 
8430 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8431 /*
8432  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8433  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8434 */
8435 {
8436  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8437  AnsiString(SpeedTag));
8438  if(!NamedLocationElementAt(2, HLoc, VLoc))
8439  {
8440  Utilities->CallLogPop(948);
8441  return(false);
8442  }
8443  bool FoundFlag;
8444  int Position = -1;
8445  TIMPair IMPair;
8446 
8447  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8448  {
8449  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8450  if(FoundFlag)
8451  {
8452  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8453  {
8454  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8455  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8456  // don't allow duplicates in either list, or processing takes a lot longer
8457  {
8458  FoundElement = MapPos;
8459  Utilities->CallLogPop(563);
8460  return(true);
8461  }
8462  }
8463  }
8464  }
8465  else
8466  {
8467  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8468  if(FoundFlag)
8469  {
8470  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8471  {
8472  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8473  {
8474  FoundElement = IMPair.first;
8475  Utilities->CallLogPop(564);
8476  return(true);
8477  }
8478  }
8479  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8480  {
8481  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8482  {
8483  FoundElement = IMPair.second;
8484  Utilities->CallLogPop(565);
8485  return(true);
8486  }
8487  }
8488  }
8489  }
8490  Utilities->CallLogPop(566);
8491  return(false);
8492 }
8493 
8494 // ---------------------------------------------------------------------------
8495 
8496 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8497 /*
8498  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8499  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8500  with the new name
8501 */
8502 {
8503  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8504  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8505 
8506  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8507  int HLoc = TrackElement->HLoc;
8508  int VLoc = TrackElement->VLoc;
8509  bool FoundFlag;
8510 
8511  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8512  // only have timetable names for adjacent platforms & named locations
8513  {
8514  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8515  if(FoundFlag)
8516  {
8517  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8518  }
8519  }
8520  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8521 
8522  if(ErrorString != "")
8523  {
8524  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8525  }
8526  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8527  CheckLocationNameMultiMap(2); // test
8528  Utilities->CallLogPop(567);
8529 }
8530 
8531 // ---------------------------------------------------------------------------
8532 
8533 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8534 /*
8535  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8536 */
8537 {
8538  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8539  if(LNDone2MultiMap.empty())
8540  {
8541  Utilities->CallLogPop(568);
8542  return(false);
8543  }
8544  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8545 
8546  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8547  {
8548  if(LNDone2MultiMapIterator->second == MapPos)
8549  {
8550  Utilities->CallLogPop(569);
8551  return(true);
8552  }
8553  }
8554  Utilities->CallLogPop(570);
8555  return(false);
8556 }
8557 
8558 // ---------------------------------------------------------------------------
8559 
8560 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8561 /*
8562  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8563 */
8564 {
8565  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8566  if(LNPendingList.empty())
8567  {
8568  Utilities->CallLogPop(571);
8569  return(false);
8570  }
8571  TLNPendingListIterator LNPendingListIterator;
8572 
8573  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8574  {
8575  if(*LNPendingListIterator == MapPos)
8576  {
8577  Utilities->CallLogPop(572);
8578  return(true);
8579  }
8580  }
8581  Utilities->CallLogPop(573);
8582  return(false);
8583 }
8584 
8585 // ---------------------------------------------------------------------------
8586 
8587 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8588 /*
8589  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8590 */
8591 {
8592  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8593  THVPair HVPair(HLoc, VLoc);
8594  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8595  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8596 
8597  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8598  {
8599  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8600  {
8601  Utilities->CallLogPop(574);
8602  return(true);
8603  }
8604  }
8605  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8606  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8607  {
8608  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8609  {
8610  Utilities->CallLogPop(575);
8611  return(true);
8612  }
8613  }
8614  Utilities->CallLogPop(576);
8615  return(false);
8616 }
8617 
8618 // ---------------------------------------------------------------------------
8619 
8620 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8621 {
8622  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8623  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8624  {
8625  Utilities->CallLogPop(1953);
8626  return(true);
8627  }
8628  Utilities->CallLogPop(1954);
8629  return(false);
8630 }
8631 
8632 // ---------------------------------------------------------------------------
8633 
8634 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8635 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8636 //program and used when try to save as a .rly file
8637 {
8638  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8641  if(LocationNameMultiMap.empty()) //no names so no duplicates
8642  {
8643  Utilities->CallLogPop(2254);
8644  return(false);
8645  }
8646  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8647  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8648  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8649  {
8651  {
8652  if(GiveMessage)
8653  {
8654  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8655  }
8656  Utilities->CallLogPop(2255);
8657  return(true);
8658  }
8659  }
8660  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8661  {
8662  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8663  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8664  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8665  {
8667  {
8668  if(GiveMessage)
8669  {
8670  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8671  }
8672  Utilities->CallLogPop(2256);
8673  return(true);
8674  }
8675  }
8676  }
8677  Utilities->CallLogPop(2257);
8678  return(false); //OK, no duplicates
8679 }
8680 
8681 // ---------------------------------------------------------------------------
8682 
8684 {
8685  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8686  THVPair HVPair;
8687  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8688  //for use in the duplicate check
8689  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8690  {
8691  if(LNMMIt->second < 0) //active track element
8692  {
8693  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8694  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8695  }
8696  else //inactive track element
8697  {
8698  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
8699  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
8700  }
8701  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
8702  }
8703  //All HVPairs now present in HVPairsLinkedMap for the specific location name
8704 
8705  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
8706  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
8707  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
8708 
8709  std::list<THVPair> HVLinkedList;
8710 
8711  //set the first value to true and add it to the list
8712  HVPairsLinkedMap.begin()->second = true;
8713  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
8714  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
8715  //examination
8716  THVPair HVPairUnderExamination;
8717  THVPairsLinkedMap::iterator HVPLMIt;
8718  THVPair HVPairNew;
8719  while(!HVLinkedList.empty())
8720  {
8721  HVPairUnderExamination = HVLinkedList.front();
8722  HVLinkedList.pop_front();
8723  HVPairNew.first = HVPairUnderExamination.first;
8724  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
8725  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8726  if(HVPLMIt != HVPairsLinkedMap.end())
8727  {
8728  if(!HVPLMIt->second)
8729  {
8730  HVLinkedList.push_back(HVPLMIt->first);
8731  }
8732  HVPLMIt->second = true;
8733  }
8734  HVPairNew.first = HVPairUnderExamination.first - 1;
8735  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
8736  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8737  if(HVPLMIt != HVPairsLinkedMap.end())
8738  {
8739  if(!HVPLMIt->second)
8740  {
8741  HVLinkedList.push_back(HVPLMIt->first);
8742  }
8743  HVPLMIt->second = true;
8744  }
8745  HVPairNew.first = HVPairUnderExamination.first;
8746  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
8747  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8748  if(HVPLMIt != HVPairsLinkedMap.end())
8749  {
8750  if(!HVPLMIt->second)
8751  {
8752  HVLinkedList.push_back(HVPLMIt->first);
8753  }
8754  HVPLMIt->second = true;
8755  }
8756  HVPairNew.first = HVPairUnderExamination.first + 1;
8757  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
8758  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8759  if(HVPLMIt != HVPairsLinkedMap.end())
8760  {
8761  if(!HVPLMIt->second)
8762  {
8763  HVLinkedList.push_back(HVPLMIt->first);
8764  }
8765  HVPLMIt->second = true;
8766  }
8767  }
8768 
8769  //at the end if any have a false bool then the name is duplicated so return false
8770  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
8771  {
8772  if(!HVPLMIt->second)
8773  {
8774  Utilities->CallLogPop(2258);
8775  return(false);
8776  }
8777  }
8778  Utilities->CallLogPop(2259);
8779  return(true);
8780 }
8781 
8782 // ---------------------------------------------------------------------------
8783 
8784 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
8785 /*
8786  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
8787 */
8788 
8789 {
8790  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
8791  if(LocationName == "")
8792  {
8793  Utilities->CallLogPop(577);
8794  return(false);
8795  }
8796 // new for v0.2b
8797 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
8799  {
8800  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
8801  ActiveTrackElementNameMap.clear();
8802  for(unsigned int x = 0; x < TrackVector.size(); x++)
8803  {
8804  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
8805  == ContinuationNameMap.end())
8806  {
8807  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
8808  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
8809  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
8810  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
8811  }
8812  }
8814  }
8815  Utilities->CallLogPop(578);
8816  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
8817 // end of new section
8818 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
8819 }
8820 
8821 // ---------------------------------------------------------------------------
8822 
8823 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
8824 /*
8825  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
8826  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
8827  new names in the vectors.
8828 */
8829 {
8830  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
8831  bool FoundFlag, ErasedFlag = false;
8832  TLocationNameMultiMapIterator SNIterator;
8833  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8834 
8835  if(SNRange.first != SNRange.second)
8836  {
8837  ErasedFlag = true;
8838  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8839  {
8840  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
8841  TVIt->LocationName = "";
8842  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8843  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
8844  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8845  {
8846  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8847  if(FoundFlag)
8848  {
8849  TrackElementAt(25, Position).LocationName = "";
8850  TrackElementAt(26, Position).ActiveTrackElementName = "";
8851  }
8852  }
8853  }
8854  }
8855  if(ErasedFlag)
8856  {
8858  }
8859  CheckLocationNameMultiMap(3); // test
8860  Utilities->CallLogPop(579);
8861 }
8862 
8863 // ---------------------------------------------------------------------------
8864 
8865 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
8866 /*
8867  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
8868  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
8869  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
8870  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
8871  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
8872  naming up to date with the deletion or insertion.
8873 */
8874 {
8875  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
8876  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
8877  LNPendingList.clear();
8878  AnsiString LocationName;
8879  int MapPos;
8880  bool FoundFlag = 0;
8881 
8882 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8883  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
8884  if(FoundFlag)
8885  {
8886  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
8887  if(LocationName != "")
8888  {
8889  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
8890  EnterLocationName(13, LocationName, true);
8891  Utilities->CallLogPop(2251);
8892  return;
8893  }
8894  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
8895  if(LocationName != "")
8896  {
8897  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
8898  EnterLocationName(14, LocationName, true);
8899  Utilities->CallLogPop(2252);
8900  return;
8901  }
8902  }
8903 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8904 
8905  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
8906  if(FoundFlag)
8907  {
8908  LocationName = TrackElementAt(1004, Position).LocationName;
8909  if(LocationName != "")
8910  {
8911  int ModifiedPosition = -1 - Position;
8912  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
8913  EnterLocationName(15, LocationName, true);
8914  Utilities->CallLogPop(2253);
8915  return;
8916  }
8917  }
8918  if(SpeedTag == 76) // top plat
8919  {
8920  for(int x = 0; x < 25; x++)
8921  {
8922  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
8923  {
8924  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8925  EnterLocationName(3, LocationName, true);
8926  break;
8927  }
8928  }
8929  }
8930  else if(SpeedTag == 77) // bot plat
8931  {
8932  for(int x = 0; x < 25; x++)
8933  {
8934  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
8935  {
8936  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8937  EnterLocationName(4, LocationName, true);
8938  break;
8939  }
8940  }
8941  }
8942  else if(SpeedTag == 78) // l plat
8943  {
8944  for(int x = 0; x < 25; x++)
8945  {
8946  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
8947  {
8948  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8949  EnterLocationName(5, LocationName, true);
8950  break;
8951  }
8952  }
8953  }
8954  else if(SpeedTag == 79) // r plat
8955  {
8956  for(int x = 0; x < 25; x++)
8957  {
8958  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
8959  {
8960  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8961  EnterLocationName(6, LocationName, true);
8962  break;
8963  }
8964  }
8965  }
8966  else if(SpeedTag == 96) // conc
8967  {
8968  for(int x = 0; x < 28; x++)
8969  {
8970  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
8971  {
8972  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8973  EnterLocationName(7, LocationName, true);
8974  break;
8975  }
8976  }
8977  }
8978  else if(SpeedTag == 129) // vert footbridge
8979  {
8980  for(int x = 0; x < 8; x++)
8981  {
8982  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
8983  {
8984  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8985  EnterLocationName(8, LocationName, true);
8986  break;
8987  }
8988  }
8989  }
8990  else if(SpeedTag == 130) // hor footbridge
8991  {
8992  for(int x = 0; x < 8; x++)
8993  {
8994  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
8995  {
8996  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8997  EnterLocationName(9, LocationName, true);
8998  break;
8999  }
9000  }
9001  }
9002  else if(SpeedTag == 145) // vert u'pass
9003  {
9004  for(int x = 0; x < 8; x++)
9005  {
9006  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
9007  {
9008  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9009  EnterLocationName(11, LocationName, true);
9010  break;
9011  }
9012  }
9013  }
9014  else if(SpeedTag == 146) // hor u'pass
9015  {
9016  for(int x = 0; x < 8; x++)
9017  {
9018  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
9019  {
9020  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9021  EnterLocationName(12, LocationName, true);
9022  break;
9023  }
9024  }
9025  }
9026  else if(SpeedTag == 131) // named location
9027  {
9028  for(int x = 0; x < 4; x++)
9029  {
9030  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
9031  {
9032  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9033  EnterLocationName(10, LocationName, true);
9034  break;
9035  }
9036  }
9037  }
9038 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
9039  Utilities->CallLogPop(580);
9040 }
9041 
9042 // ---------------------------------------------------------------------------
9043 
9044 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
9045 /*
9046  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
9047  true if a LocationName is found, and also returns the name and the adjusted vector position.
9048 */
9049 {
9050  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9051  AnsiString(SpeedTag));
9052  bool FoundFlag;
9053  TIMPair IMPair;
9054  TTrackVectorIterator TempElement;
9055  int Position;
9056 
9057  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
9058  if(FoundFlag)
9059  {
9060  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
9061  {
9062  TempElement = InactiveTrackVector.begin() + IMPair.first;
9063  if(TempElement->LocationName != "")
9064  {
9065  LocationName = TempElement->LocationName;
9066  FoundElement = IMPair.first;
9067  Utilities->CallLogPop(581);
9068  return(true);
9069  }
9070  }
9071  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
9072  {
9073  TempElement = InactiveTrackVector.begin() + IMPair.second;
9074  if(TempElement->LocationName != "")
9075  {
9076  LocationName = TempElement->LocationName;
9077  FoundElement = IMPair.second;
9078  Utilities->CallLogPop(582);
9079  return(true);
9080  }
9081  }
9082  }
9083  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
9084  if(FoundFlag)
9085  {
9086  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
9087  {
9088  TempElement = TrackVector.begin() + Position;
9089  if(TempElement->LocationName != "")
9090  {
9091  LocationName = TempElement->LocationName;
9092  FoundElement = -1 - Position;
9093  Utilities->CallLogPop(583);
9094  return(true);
9095  }
9096  }
9097  }
9098  Utilities->CallLogPop(584);
9099  return(false);
9100 }
9101 
9102 // ---------------------------------------------------------------------------
9103 
9104 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
9105 {
9106 // check quantity in map & vectors match
9107  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
9108  unsigned int Count = 0;
9109 
9110  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
9111  {
9112  Utilities->CallLogPop(2059);
9113  return;
9114  }
9115  AnsiString SName, TName, ErrorString;
9116 
9117  for(unsigned int x = 0; x < TrackVector.size(); x++)
9118  {
9119  if(TrackElementAt(1362, x).FixedNamedLocationElement)
9120  {
9121  if(TrackElementAt(1363, x).TrackType != FootCrossing)
9122  {
9123  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
9124  AnsiString(Caller));
9125  }
9126  Count++;
9127  }
9128  }
9129  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9130  {
9131  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
9132  {
9133  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
9134  (InactiveTrackElementAt(146, x).TrackType != Concourse))
9135  {
9136  throw Exception
9137  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
9138  AnsiString(Caller));
9139  }
9140  Count++;
9141  }
9142  }
9143  if(LocationNameMultiMap.size() != Count)
9144  {
9145  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
9146  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9147  }
9148 // check all entries in both vectors match entries in name multimap
9150 
9151  for(unsigned int x = 0; x < TrackVector.size(); x++)
9152  {
9153  if(TrackElementAt(1364, x).FixedNamedLocationElement)
9154  {
9155  SName = TrackElementAt(1365, x).LocationName;
9156  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
9157  if(ErrorString != "")
9158  {
9159  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
9160  }
9161  if(SNIt->second != -1 - (int)x)
9162  {
9163  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9164  AnsiString(Caller));
9165  }
9166  }
9167  // check corresponding platform for all Timetable entries that aren't empty
9168  TName = TrackElementAt(1366, x).ActiveTrackElementName;
9169  TIMPair IMPair;
9170  bool FoundFlag = false;
9171  if(TName != "")
9172  {
9173  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
9174  if(FoundFlag)
9175  {
9176  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
9178  {
9179  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
9180  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9181  }
9182  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9183  {
9184  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9185  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9186  AnsiString(Caller));
9187  }
9188  }
9189  else
9190  {
9191  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9192  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9193  }
9194  }
9195  }
9196  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9197  {
9198  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9199  {
9200  SName = InactiveTrackElementAt(148, x).LocationName;
9201  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9202  if(ErrorString != "")
9203  {
9204  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9205  }
9206  if(SNIt->second != (int)x)
9207  {
9208  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9209  AnsiString(Caller));
9210  }
9211  }
9212  }
9213  Utilities->CallLogPop(585);
9214 }
9215 
9216 // ---------------------------------------------------------------------------
9217 
9219  AnsiString &ErrorString)
9220 {
9221 /*
9222  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9223  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9224  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9225 */
9226  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9227  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9228  ErrorString = "";
9229  bool FoundFlag = false;
9230  TLocationNameMultiMapIterator SNIterator;
9231  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9232 
9233  if(SNRange.first == SNRange.second)
9234  {
9235  ErrorString = "Error, Name " + LocationName + " not found in map";
9236  Utilities->CallLogPop(586);
9237  return(SNRange.first);
9238  }
9239  else
9240  {
9241  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9242  {
9243  if(SNIterator->second < 0)
9244  {
9245  int TVPos = -1 - SNIterator->second;
9246  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9247  if(TVIt == TrackElement)
9248  {
9249  FoundFlag = true;
9250  Utilities->CallLogPop(587);
9251  return(SNIterator);
9252  }
9253  }
9254  else
9255  {
9256  int ITVPos = SNIterator->second;
9257  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9258  if(ITVIt == TrackElement)
9259  {
9260  FoundFlag = true;
9261  Utilities->CallLogPop(588);
9262  return(SNIterator);
9263  }
9264  }
9265  }
9266  }
9267  if(!FoundFlag)
9268  {
9269  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9270  }
9271  Utilities->CallLogPop(589);
9272  return(SNIterator);
9273 }
9274 
9275 // ---------------------------------------------------------------------------
9276 
9277 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9278 {
9279 /*
9280  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9281  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9282 */
9283  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9284  TLocationNameMultiMapEntry LocationNameEntry;
9285 
9286  LocationNameEntry.first = NewName;
9287  LocationNameEntry.second = SNIterator->second;
9288  LocationNameMultiMap.erase(SNIterator);
9289  LocationNameMultiMap.insert(LocationNameEntry);
9290  Utilities->CallLogPop(590);
9291 }
9292 
9293 // ---------------------------------------------------------------------------
9294 
9296 {
9297 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9298  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9299  if(Position < 0) // footcrossing
9300  {
9301  int TruePos = -1 - Position;
9302  // new check at v0.2b
9303  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9304  {
9305  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9306  }
9307  Utilities->CallLogPop(591);
9308  return (TrackVector.begin() + TruePos);
9309  }
9310  else
9311  {
9312  // new check at v0.2b
9313  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9314  {
9315  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9316  }
9317  Utilities->CallLogPop(592);
9318  return (InactiveTrackVector.begin() + Position);
9319  }
9320 }
9321 
9322 // ---------------------------------------------------------------------------
9323 
9324 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9325 {
9326 /*
9327  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9328  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9329  LocationNameMultiMap.
9330 */
9331  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9332  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9333  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9334 
9335  if(!InactiveTrack2MultiMap.empty())
9336  {
9337  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9338  InactiveTrack2MultiMapIterator++)
9339  {
9340  if(InactiveTrack2MultiMapIterator->second > VecPos)
9341  {
9342  InactiveTrack2MultiMapIterator->second--;
9343  }
9344  // can't be == VecPos as that position erased
9345  }
9346  }
9347  if(!LocationNameMultiMap.empty())
9348  {
9349  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9350  LocationNameMultiMapIterator++)
9351  {
9352  if(LocationNameMultiMapIterator->second < 0)
9353  {
9354  continue; // deal with TrackVectors separately
9355  }
9356  if(LocationNameMultiMapIterator->second > (int)VecPos)
9357  {
9358  LocationNameMultiMapIterator->second--;
9359  }
9360  }
9361  }
9362  Utilities->CallLogPop(593);
9363 }
9364 
9365 // ---------------------------------------------------------------------------
9366 
9367 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9368 {
9369 /*
9370  After an element has been erased from the track vector, all the later elements are moved down one. This function
9371  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9372  LocationNameMultiMap.
9373 */
9374  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9375  TTrackMapIterator TrackMapIterator;
9376  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9377 
9378  if(!TrackMap.empty())
9379  {
9380  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9381  {
9382  if(TrackMapIterator->second > VecPos)
9383  {
9384  TrackMapIterator->second--;
9385  }
9386  // can't be == VecPos as that position erased
9387  }
9388  }
9389  if(!LocationNameMultiMap.empty())
9390  {
9391  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9392  LocationNameMultiMapIterator++)
9393  {
9394  if(LocationNameMultiMapIterator->second >= 0)
9395  {
9396  continue; // deal with InactiveTrackVectors separately
9397  }
9398  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9399  // Val -1 -2 -3 -4 -5 -6 -7 -8
9400  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9401  {
9402  LocationNameMultiMapIterator->second++;
9403  }
9404  }
9405  }
9406  for(unsigned int x = 0; x < TrackVector.size(); x++)
9407  {
9408  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9409  if(TkEl.TrackType == GapJump)
9410  {
9411  // position 0 is the gap
9412  if(TkEl.Conn[0] == int(VecPos))
9413  {
9414  TkEl.Conn[0] = -1; // connected to a deleted gap
9415  continue;
9416  }
9417  if(TkEl.Conn[0] > int(VecPos))
9418  {
9419  TkEl.Conn[0]--;
9420  }
9421  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9422  {
9423  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9424  {
9425  TkEl.Conn[0] = -1;
9426  }
9427  }
9428  }
9429  }
9430  Utilities->CallLogPop(1433);
9431 }
9432 
9433 // ---------------------------------------------------------------------------
9434 
9436 /*
9437  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9438  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9439  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9440 */
9441 {
9442  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9443  LocationNameMultiMap.clear();
9444  TLocationNameMultiMapEntry LocationNameEntry;
9445  TTrackElement TrackElement;
9446 
9447  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9448  {
9449  TrackElement = TrackElementAt(1376, TVPos);
9450  if(TrackElement.FixedNamedLocationElement)
9451  {
9452  LocationNameEntry.first = TrackElement.LocationName;
9453  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9454  LocationNameMultiMap.insert(LocationNameEntry);
9455  }
9456  }
9457 
9458  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9459  {
9460  TrackElement = InactiveTrackElementAt(149, ITVPos);
9461  if(TrackElement.FixedNamedLocationElement)
9462  {
9463  LocationNameEntry.first = TrackElement.LocationName;
9464  LocationNameEntry.second = ITVPos;
9465  LocationNameMultiMap.insert(LocationNameEntry);
9466  }
9467  }
9468  Utilities->CallLogPop(594);
9469 }
9470 
9471 // ---------------------------------------------------------------------------
9472 
9474 // Return true if there is a named location present in the railway
9475 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9476 {
9477  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9478  TTrackVectorIterator ITVI;
9479 
9480  if(InactiveTrackVector.empty())
9481  {
9482  Utilities->CallLogPop(1343);
9483  return(false);
9484  }
9485  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9486  {
9487  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9488  {
9489  Utilities->CallLogPop(1404);
9490  return(true);
9491  }
9492  }
9493  Utilities->CallLogPop(1344);
9494  return(false);
9495 }
9496 
9497 // ---------------------------------------------------------------------------
9498 
9500 /*
9501  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9502 */
9503 {
9504  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9505 // ResetDistanceElements(6);
9506  for(unsigned int x = 0; x < TrackVector.size(); x++)
9507  {
9508  TTrackElement &TE = TrackElementAt(718, x);
9511  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9512  {
9515  }
9516  }
9517 /* old function
9518  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9519  {
9520  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9521  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9522  }
9523  else
9524  {
9525  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9526  }
9527  }
9528 */
9529  Utilities->CallLogPop(617);
9530 }
9531 
9532 // ---------------------------------------------------------------------------
9533 
9534 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
9535 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
9536 {
9537  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
9538  for(unsigned int x = 0; x < TrackVector.size(); x++)
9539  {
9540  TTrackElement TempElement = TrackElementAt(1377, x);
9541  if(TempElement.Length01 > -1)
9542  {
9543  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9544  }
9545  if(TempElement.Length23 > -1)
9546  {
9547  MarkOneLength(2, TempElement, false, Disp);
9548  }
9549  }
9550  Disp->Update();
9551  Utilities->CallLogPop(618);
9552 }
9553 
9554 // ---------------------------------------------------------------------------
9555 
9556 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
9557 /*
9558  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h normally but can be changed in Config.txt
9559  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
9560  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
9561  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
9562  track as indicated by FirstTrack (true for track01 & false for track23).
9563 */
9564 {
9565  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
9566  AnsiString((short)FirstTrack));
9567  bool LengthDifferent = false, SpeedDifferent = false;
9568 
9569  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
9570  {
9571  Utilities->CallLogPop(619);
9572  return;
9573  }
9574  int EXArray[16][2] =
9575  {{4, 6}, {2, 8}, // horizontal & vertical
9576  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9577  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9578  {1, 9}, {3, 7}}; // forward & reverse diagonals
9579 
9580  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
9581  Graphics::TBitmap *Bitmap;
9582 
9583  if(FirstTrack)
9584  {
9585  InLink = TrackElement.Link[0];
9586  OutLink = TrackElement.Link[1];
9587  }
9588  else
9589  {
9590  InLink = TrackElement.Link[2];
9591  OutLink = TrackElement.Link[3];
9592  }
9593  for(int x = 0; x < 16; x++)
9594  {
9595  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9596  {
9597  Index = x;
9598  }
9599  }
9600  if(Index == -1)
9601  {
9602  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
9603  }
9604 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9605  the graphic for each of which is different because of the shape of the overbridge. The basic
9606  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9607  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9608  int BrEXArray[24][2] = {
9609  {4,6},{2,8},{1,9},{3,7},
9610  {1,9},{3,7},{1,9},{3,7},
9611  {2,8},{4,6},{2,8},{4,6}
9612 */
9613  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9614  {
9615  if(Index == 1)
9616  {
9617  if(TrackElement.SpeedTag == 49)
9618  {
9619  BrNum = 1 + 16;
9620  }
9621  else if(TrackElement.SpeedTag == 54)
9622  {
9623  BrNum = 8 + 16;
9624  }
9625  else if(TrackElement.SpeedTag == 55)
9626  {
9627  BrNum = 10 + 16;
9628  }
9629  }
9630  else if(Index == 0)
9631  {
9632  if(TrackElement.SpeedTag == 48)
9633  {
9634  BrNum = 0 + 16;
9635  }
9636  else if(TrackElement.SpeedTag == 58)
9637  {
9638  BrNum = 11 + 16;
9639  }
9640  else if(TrackElement.SpeedTag == 59)
9641  {
9642  BrNum = 9 + 16;
9643  }
9644  }
9645  else if(Index == 14)
9646  {
9647  if(TrackElement.SpeedTag == 50)
9648  {
9649  BrNum = 2 + 16;
9650  }
9651  else if(TrackElement.SpeedTag == 52)
9652  {
9653  BrNum = 4 + 16;
9654  }
9655  else if(TrackElement.SpeedTag == 57)
9656  {
9657  BrNum = 6 + 16;
9658  }
9659  }
9660  else if(Index == 15)
9661  {
9662  if(TrackElement.SpeedTag == 51)
9663  {
9664  BrNum = 3 + 16;
9665  }
9666  else if(TrackElement.SpeedTag == 53)
9667  {
9668  BrNum = 7 + 16;
9669  }
9670  else if(TrackElement.SpeedTag == 56)
9671  {
9672  BrNum = 5 + 16;
9673  }
9674  }
9675  }
9676  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9677  {
9678  GrNum = BrNum;
9679  }
9680  else
9681  {
9682  GrNum = Index;
9683  }
9684  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
9685  {
9686  if(GrNum > 15) // underbridge
9687  {
9688  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
9689  }
9690  else
9691  {
9692  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
9693  }
9694  if(TrackElement.SpeedTag == 64)
9695  {
9696  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9697  }
9698  if(TrackElement.SpeedTag == 65)
9699  {
9701  }
9702  if(TrackElement.SpeedTag == 66)
9703  {
9705  }
9706  if(TrackElement.SpeedTag == 67)
9707  {
9709  }
9710  if(TrackElement.SpeedTag == 80)
9711  {
9712  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
9713  }
9714  if(TrackElement.SpeedTag == 81)
9715  {
9717  }
9718  if(TrackElement.SpeedTag == 82)
9719  {
9721  }
9722  if(TrackElement.SpeedTag == 83)
9723  {
9725  }
9726  if(TrackElement.SpeedTag == 84)
9727  {
9729  }
9730  if(TrackElement.SpeedTag == 85)
9731  {
9733  }
9734  if(TrackElement.SpeedTag == 86)
9735  {
9737  }
9738  if(TrackElement.SpeedTag == 87)
9739  {
9741  }
9742  if(TrackElement.SpeedTag == 129)
9743  {
9744  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
9745  }
9746  if(TrackElement.SpeedTag == 130)
9747  {
9749  }
9750  }
9751 
9752  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
9753  {
9754  if(GrNum > 15) // underbridge
9755  {
9756  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
9757  }
9758  else
9759  {
9760  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
9761  }
9762  if(TrackElement.SpeedTag == 64)
9763  {
9764  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9765  }
9766  if(TrackElement.SpeedTag == 65)
9767  {
9768  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
9769  }
9770  if(TrackElement.SpeedTag == 66)
9771  {
9772  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
9773  }
9774  if(TrackElement.SpeedTag == 67)
9775  {
9776  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
9777  }
9778  if(TrackElement.SpeedTag == 80)
9779  {
9780  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9781  }
9782  if(TrackElement.SpeedTag == 81)
9783  {
9784  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
9785  }
9786  if(TrackElement.SpeedTag == 82)
9787  {
9788  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
9789  }
9790  if(TrackElement.SpeedTag == 83)
9791  {
9792  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
9793  }
9794  if(TrackElement.SpeedTag == 84)
9795  {
9796  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
9797  }
9798  if(TrackElement.SpeedTag == 85)
9799  {
9800  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
9801  }
9802  if(TrackElement.SpeedTag == 86)
9803  {
9804  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
9805  }
9806  if(TrackElement.SpeedTag == 87)
9807  {
9808  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
9809  }
9810  if(TrackElement.SpeedTag == 129)
9811  {
9812  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
9813  }
9814  if(TrackElement.SpeedTag == 130)
9815  {
9816  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
9817  }
9818  }
9819 
9820  else // SpeedDifferent only: red - use non sig graphics
9821  {
9822  if(GrNum > 15) // underbridge
9823  {
9824  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
9825  }
9826  else
9827  {
9828  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
9829  }
9830  if(TrackElement.SpeedTag == 64)
9831  {
9832  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9833  }
9834  if(TrackElement.SpeedTag == 65)
9835  {
9837  }
9838  if(TrackElement.SpeedTag == 66)
9839  {
9841  }
9842  if(TrackElement.SpeedTag == 67)
9843  {
9845  }
9846  if(TrackElement.SpeedTag == 80)
9847  {
9848  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9849  }
9850  if(TrackElement.SpeedTag == 81)
9851  {
9853  }
9854  if(TrackElement.SpeedTag == 82)
9855  {
9857  }
9858  if(TrackElement.SpeedTag == 83)
9859  {
9861  }
9862  if(TrackElement.SpeedTag == 84)
9863  {
9865  }
9866  if(TrackElement.SpeedTag == 85)
9867  {
9869  }
9870  if(TrackElement.SpeedTag == 86)
9871  {
9873  }
9874  if(TrackElement.SpeedTag == 87)
9875  {
9877  }
9878  if(TrackElement.SpeedTag == 129)
9879  {
9880  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
9881  }
9882  if(TrackElement.SpeedTag == 130)
9883  {
9885  }
9886  }
9887  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
9888  Utilities->CallLogPop(620);
9889 }
9890 
9891 // ---------------------------------------------------------------------------
9892 
9893 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
9894 /* FirstTrack = LinkPos's 0 & 1
9895  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
9896 */
9897 {
9898  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
9899  AnsiString((short)FirstTrack));
9900  LengthDifferent = false;
9901  SpeedDifferent = false;
9902  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
9903  {
9904  if(TrackElement.Length01 != DefaultTrackLength)
9905  {
9906  LengthDifferent = true;
9907  }
9908  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9909  {
9910  SpeedDifferent = true;
9911  }
9912  if(LengthDifferent || SpeedDifferent)
9913  {
9914  Utilities->CallLogPop(625);
9915  return(false);
9916  }
9917  Utilities->CallLogPop(626);
9918  return(true);
9919  }
9920 
9921  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
9922  {
9923  if(TrackElement.Length23 != DefaultTrackLength)
9924  {
9925  LengthDifferent = true;
9926  }
9927  if(TrackElement.SpeedLimit23 != DefaultTrackSpeedLimit)
9928  {
9929  SpeedDifferent = true;
9930  }
9931  if(LengthDifferent || SpeedDifferent)
9932  {
9933  Utilities->CallLogPop(627);
9934  return(false);
9935  }
9936  Utilities->CallLogPop(628);
9937  return(true);
9938  }
9939 
9940  else // any other 1 track element, including platforms being present
9941  {
9942  if(TrackElement.Length01 != DefaultTrackLength)
9943  {
9944  LengthDifferent = true;
9945  }
9946  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9947  {
9948  SpeedDifferent = true;
9949  }
9950  if(LengthDifferent || SpeedDifferent)
9951  {
9952  Utilities->CallLogPop(629);
9953  return(false);
9954  }
9955  Utilities->CallLogPop(630);
9956  return(true);
9957  }
9958 }
9959 
9960 // ---------------------------------------------------------------------------
9961 
9962 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9963 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
9964 {
9965  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9966  AnsiString(VLoc));
9967  bool FoundFlag;
9968  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
9969 
9970  if(!FoundFlag)
9971  {
9972  Utilities->CallLogPop(633);
9973  return(false);
9974  }
9975  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
9976  {
9977  Utilities->CallLogPop(634);
9978  return(true); // only need to check first since if second is a platform the the first must be too
9979  }
9980  else
9981  {
9982  Utilities->CallLogPop(635);
9983  return(false);
9984  }
9985 }
9986 
9987 // ---------------------------------------------------------------------------
9988 
9989 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9990 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
9991 {
9992  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9993  AnsiString(VLoc));
9994  bool FoundFlag;
9995  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
9996 
9997  if(!FoundFlag)
9998  {
9999  Utilities->CallLogPop(636);
10000  return(false);
10001  }
10003  {
10004  Utilities->CallLogPop(637);
10005  return(true); // only need to check first since only one used for NamedNonStationLocations
10006  }
10007  else
10008  {
10009  Utilities->CallLogPop(638);
10010  return(false);
10011  }
10012 }
10013 
10014 // ---------------------------------------------------------------------------
10015 
10017 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
10018  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
10019  the front of train stop points for each direction.
10020  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
10021  end (unless buffers at one or both ends in which case stop points are the end elements).
10022  Note that for a single element the stop point is the element itself (formula doesn't apply).
10023  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
10024  repeating the procedure for every element. At the end all unused values are returned to -1.
10025  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
10026 */
10027 {
10028  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
10029  TTrackElement TempElement, StartElement;
10030  AnsiString TempName;
10031  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
10032  bool ForwardSet, ReverseSet;
10033 
10034  for(unsigned int x = 0; x < TrackVector.size(); x++)
10035  {
10038  }
10039  for(unsigned int x = 0; x < TrackVector.size(); x++)
10040  {
10041  ForwardSet = false;
10042  ReverseSet = false;
10043  TempElement = TrackElementAt(1380, x);
10044  VecPos = x;
10045  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
10046  // 2nd condition incl so don't re-examine elements with stop links set to 5
10047  {
10048  TempName = TempElement.ActiveTrackElementName;
10049  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10050  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10051  // an element linked at both ends where both links are also named elements
10052  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
10053  {
10054  continue; // looking for an end element so skip this one
10055  }
10056  else // reached one end
10057  {
10058  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
10059  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10060  // single named element linked at both ends
10061  {
10062  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
10063  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
10064  continue;
10065  }
10066  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10067  // single named buffer element (LinkPos 1 is the non-buffer end)
10068  {
10069  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
10070  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
10071  continue;
10072  }
10073  else
10074  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
10075  // and platforms always on straight (conns 0 & 1) section of points
10076  {
10077  for(int y = 0; y < 2; y++)
10078  {
10079  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
10080  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
10081 /* TTrackElement Temp1 = TempElement;
10082  ***********New section, compiles but not checked - does bit below need to be else if?
10083  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
10084  {
10085  //search along Dir direction until find other end, skip if Dir facing buffer end
10086  int NewDir = Dir;
10087  int NewVecPos;
10088  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
10089  {
10090  NewVecPos = Temp1.Conn[NewDir];
10091  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
10092  Temp1 = TrackElementAt(601, NewVecPos);
10093  }
10094  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
10095  {
10096  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
10097  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
10098  }
10099  }
10100  ***************
10101 */
10102  // end may be linked at both ends but only one link named, or buffer with linked element named
10103  // if a buffer then the named linkpos has to be 1
10104  // already dealt with all types of single element so at least 2 linked named element
10105  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
10106  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
10107  {
10108  StartElement = TempElement;
10109  StartVecPos = VecPos;
10110  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
10111  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
10112  EntryPos = 1 - Dir;
10113  StartEntryPos = 1 - Dir;
10114  Count = 1;
10115  // work along named elements until find the other end
10116  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
10117  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
10118  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
10119  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
10120  // all stop link pos's are set to 5
10121  {
10122  VecPos = TempElement.Conn[1 - EntryPos];
10123  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10124  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
10125  EntryPos = TempEntryPos;
10126  Count++;
10127  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
10128  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
10129  }
10130  // here when reached other end, maybe buffers, continuation or last named linked element
10131  if(TrackElementAt(57, VecPos).TrackType == Buffers)
10132  // terminal station, set end elements as stop elements
10133  {
10134  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
10135  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
10136  continue;
10137  }
10138  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
10139  // terminal station, set end elements as stop elements
10140  {
10141  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
10142  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10143  continue;
10144  }
10145  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
10146  // NonStationLocation so set end elements as stop elements
10147  {
10148  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
10149  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10150  continue;
10151  }
10152  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
10153  ForwardNumber = ((Count + 1) / 2) + 1;
10154  ReverseNumber = (Count - ForwardNumber) + 1;
10155  Count = 1; // starting value
10156  EntryPos = 1 - Dir;
10157  TempElement = StartElement;
10158  VecPos = StartVecPos;
10159  if(Count == ForwardNumber)
10160  {
10161  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
10162  ForwardSet = true;
10163  }
10164  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
10165  {
10166  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10167  ReverseSet = true;
10168  }
10169  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
10170  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
10171  {
10172  VecPos = TempElement.Conn[1 - EntryPos];
10173  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10174  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
10175  EntryPos = TempEntryPos;
10176  Count++;
10177  if(Count == ForwardNumber)
10178  {
10179  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
10180  ForwardSet = true;
10181  }
10182  if(Count == ReverseNumber)
10183  {
10184  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10185  ReverseSet = true;
10186  }
10187  }
10188  }
10189  }
10190  }
10191  }
10192  }
10193  }
10194  for(unsigned int x = 0; x < TrackVector.size(); x++)
10195  {
10196  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10197  {
10199  }
10200  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10201  {
10203  }
10204  }
10205  Utilities->CallLogPop(639);
10206 }
10207 
10208 // ---------------------------------------------------------------------------
10209 
10210 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10211 {
10212  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10213  TTrackElement Next;
10214 
10216  while(ReturnNextInactiveTrackElement(1, Next))
10217  {
10218  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10219  {
10220  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10221  // need striped graphics
10222  {
10223  if(Next.SpeedTag == 76)
10224  {
10225  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10226  }
10227  else if(Next.SpeedTag == 77)
10228  {
10229  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10230  }
10231  else if(Next.SpeedTag == 78)
10232  {
10233  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10234  }
10235  else if(Next.SpeedTag == 79)
10236  {
10237  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10238  }
10239  else if(Next.SpeedTag == 96)
10240  {
10241  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10242  }
10243  else if(Next.SpeedTag == 131)
10244  {
10245  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10246  }
10247  }
10248  else
10249  {
10250  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10251  }
10252  }
10253  }
10254 
10255  NextTrackElementPtr = TrackVector.begin();
10256  while(ReturnNextTrackElement(1, Next))
10257  {
10258  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10259  {
10260  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10261  {
10262  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10263  {
10264  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10265  }
10266  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10267  {
10268  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10269  }
10270  }
10271  else
10272  {
10273  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10274  }
10275  }
10276  }
10277  Disp->Update();
10278  Utilities->CallLogPop(640);
10279 }
10280 
10281 // ---------------------------------------------------------------------------
10282 
10283 void TTrack::PlotSmallRedGap(int Caller)
10284 {
10285  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10287  Utilities->CallLogPop(1346);
10288 }
10289 
10290 // ---------------------------------------------------------------------------
10291 
10292 void TTrack::TrackClear(int Caller)
10293 {
10294  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
10295  TrackVector.clear();
10296  InactiveTrackVector.clear();
10297  TrackMap.clear();
10299  if(TextHandler->TextVector.size() == 0)
10300  {
10301  Display->DisplayOffsetH = 0;
10302  Display->DisplayOffsetV = 0;
10309  HLocMin = 2000000000;
10310  HLocMax = -2000000000;
10311  VLocMin = 2000000000;
10312  VLocMax = -2000000000;
10313  }
10314  else
10315  {
10316  CalcHLocMinEtc(4);
10317  }
10318  Utilities->CallLogPop(1347);
10319 }
10320 
10321 // ---------------------------------------------------------------------------
10322 
10323 void TTrack::CalcHLocMinEtc(int Caller)
10324 {
10325  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
10326  HLocMin = 2000000000;
10327  VLocMin = 2000000000;
10328  HLocMax = -2000000000;
10329  VLocMax = -2000000000;
10330  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
10331  {
10332  if(TrackElementAt(1385, x).SpeedTag == 0)
10333  {
10334  continue; // skip erase elements or would interfere with Min & Max values
10335  }
10336  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
10337  {
10338  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
10339  }
10340  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
10341  {
10342  HLocMax = TrackElementAt(1389, x).HLoc + 1;
10343  }
10344  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
10345  {
10346  VLocMin = TrackElementAt(1391, x).VLoc - 1;
10347  }
10348  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
10349  {
10350  VLocMax = TrackElementAt(1393, x).VLoc + 1;
10351  }
10352  }
10353  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
10354  {
10355  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
10356  {
10357  continue; // shouldn't be any inactive erase elements but include anyway
10358  }
10359  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
10360  {
10361  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
10362  }
10363  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
10364  {
10365  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
10366  }
10367  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
10368  {
10369  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
10370  }
10371  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
10372  {
10373  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
10374  }
10375  }
10376  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
10377  {
10378 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
10379  will fail as x will exceed the maximum value
10380  if(TextHandler->TextPtrAt(, x)->TextString == "")
10381  {
10382  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
10383  }
10384 */
10385  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
10386  if((TextH / 16) - 1 < HLocMin)
10387  {
10388  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
10389  }
10390  if((TextH / 16) + 1 > HLocMax)
10391  {
10392  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
10393  }
10394  if((TextV / 16) - 1 < VLocMin)
10395  {
10396  VLocMin = (TextV / 16) - 1;
10397  }
10398  if((TextV / 16) + 1 > VLocMax)
10399  {
10400  VLocMax = (TextV / 16) + 1;
10401  }
10402  }
10403  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
10404  {
10405  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
10406  {
10407  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
10408  }
10409  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
10410  {
10411  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
10412  }
10413  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
10414  {
10415  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
10416  }
10417  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
10418  {
10419  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
10420  }
10421  }
10422 
10423  Utilities->CallLogPop(641);
10424 }
10425 
10426 // ---------------------------------------------------------------------------
10427 
10428 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
10429  bool &UserGraphicFoundFlag)
10430 {
10431  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
10432  TUserGraphicVector::iterator UserGraphicPtr;
10433 
10434  UserGraphicFoundFlag = false;
10435  if(!UserGraphicVector.empty())
10436  {
10437  int x = UserGraphicVector.size();
10438  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
10439  {
10440  x--;
10441  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
10442  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
10443  {
10444  UserGraphicItem = x;
10445  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
10446  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
10447  UserGraphicFoundFlag = true;
10448  Utilities->CallLogPop(2177);
10449  return;
10450  } // if ....
10451 
10452  } // for UserGraphicPtr...
10453  } // if !UserGraphicVector...
10454 
10455  Utilities->CallLogPop(2197);
10456 }
10457 
10458 // ---------------------------------------------------------------------------
10459 
10461 {
10462  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
10463  TrackElement.LogTrack(11));
10464  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
10465  int SpeedTag = TrackElement.SpeedTag;
10466 
10467  if(SpeedTag < 1)
10468  {
10469  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
10470  }
10471  switch(SpeedTag)
10472  {
10473  case 76: // t platform
10474  GraphicOutput = RailGraphics->gl76Striped;
10475  break;
10476 
10477  case 77: // h platform
10478  GraphicOutput = RailGraphics->bm77Striped;
10479  break;
10480 
10481  case 78: // v platform
10482  GraphicOutput = RailGraphics->bm78Striped;
10483  break;
10484 
10485  case 79: // r platform
10486  GraphicOutput = RailGraphics->gl79Striped;
10487  break;
10488 
10489  case 96: // concourse
10490  GraphicOutput = RailGraphics->ConcourseStriped;
10491  break;
10492 
10493  case 129: // v footbridge
10494  GraphicOutput = RailGraphics->gl129Striped;
10495  break;
10496 
10497  case 130: // h footbridge
10498  GraphicOutput = RailGraphics->gl130Striped;
10499  break;
10500 
10501  case 131: // non-station named loc
10502  GraphicOutput = RailGraphics->bmNameStriped;
10503  break;
10504 
10505  case 145: // v u'pass
10506  GraphicOutput = RailGraphics->gl145Striped;
10507  break;
10508 
10509  case 146: // h u'pass
10510  GraphicOutput = RailGraphics->gl146Striped;
10511  break;
10512 
10513  default:
10514  GraphicOutput = TrackElement.GraphicPtr;
10515  break;
10516  }
10517  Utilities->CallLogPop(642);
10518  return(GraphicOutput);
10519 }
10520 
10521 // ---------------------------------------------------------------------------
10522 
10524 {
10525  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
10526  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10527  {
10528 // Utilities->CallLogPop(2281); this shouldn't be here, introduced 02/06/21 at revision 3745fadb... with no explanation
10529  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
10530  }
10531  Utilities->CallLogPop(643);
10532  return(TrackVector.at(At));
10533 }
10534 
10535 // ---------------------------------------------------------------------------
10536 
10538 {
10539  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
10540  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
10541  {
10542  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
10543  " in InactiveTrackElementAt");
10544  }
10545  Utilities->CallLogPop(644);
10546  return(InactiveTrackVector.at(At));
10547 }
10548 
10549 // ---------------------------------------------------------------------------
10550 
10551 bool TTrack::BlankElementAt(int Caller, int At) const
10552 {
10553  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
10554  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10555  {
10556  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
10557  }
10558  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
10559  {
10560  Utilities->CallLogPop(645);
10561  return(true);
10562  }
10563  else
10564  {
10565  Utilities->CallLogPop(646);
10566  return(false);
10567  }
10568 }
10569 
10570 // ---------------------------------------------------------------------------
10571 
10572 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
10573 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
10574  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
10575  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
10576  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
10577  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
10578 */
10579 {
10580  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
10581  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10582  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10583  TLocationNameMultiMapIterator SNIterator;
10584  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10585 
10586  if(SNRange.first == SNRange.second)
10587  {
10588  Utilities->CallLogPop(972);
10589  return(false); // should have been caught earlier but include for completeness
10590  }
10591  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10592  {
10593  if(SNIterator->second < 0)
10594  {
10595  continue; // exclude footcrossings
10596  }
10597  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
10598  if(InactiveElement.TrackType == Concourse)
10599  {
10600  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
10601  }
10602  if(!TrackElementPresentAtHV(1, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
10603  {
10604  continue; // only interested in locations where ActiveTrackElementName may be set
10605  }
10606  THVPair HVPair;
10607  HVPair.first = InactiveElement.HLoc;
10608  HVPair.second = InactiveElement.VLoc;
10609  if(TrackMap.find(HVPair) == TrackMap.end())
10610  {
10611  throw Exception
10612  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
10613  }
10614  int TVPos = TrackMap.find(HVPair)->second;
10615  FirstNamedElement = TrackElementAt(560, TVPos);
10616  // first check linked on both sides, skip the check if not
10617  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10618  {
10619  continue;
10620  }
10621  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10622  // ActiveTrackElementNames are points and excluding trailing connections for points
10623  FirstNamedExitPos = 0;
10624  {
10625  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
10626  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10627  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10628  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10629  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10630  {
10631  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10632  {
10633  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
10634  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10635  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10636  // success, now check FirstNamedElement link not trailing points & if so all OK
10637  {
10638  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10639  {
10640  Utilities->CallLogPop(1002);
10641  return(true);
10642  }
10643  }
10644  }
10645  }
10646  }
10647  // failed, try link 1
10648  FirstNamedExitPos = 1;
10649  {
10650  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
10651  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10652  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10653  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10654  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10655  {
10656  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10657  {
10658  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
10659  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10660  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10661  // success, now check FirstNamedElement link not trailing points & if so all OK
10662  {
10663  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10664  {
10665  Utilities->CallLogPop(1003);
10666  return(true);
10667  }
10668  }
10669  }
10670  }
10671  }
10672  }
10673  Utilities->CallLogPop(1004);
10674  return(false);
10675 }
10676 
10677 // ---------------------------------------------------------------------------
10678 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
10679  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
10680 // for success need two linked named location elements, so that one element of each train can be at the location
10681 // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
10682 // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
10683 // the two trains will occupy these 4 elements
10684 // All are track vector positions, all but the input being references and set within the function.
10685 {
10686 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
10687  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
10688  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
10689  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
10690  splitting.
10691 */
10692  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
10693  AnsiString(FirstNamedElementPos));
10694  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10695  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10696 
10697  SecondNamedElementPos = -1;
10698  FirstNamedLinkedElementPos = -1;
10699  SecondNamedLinkedElementPos = -1;
10700  TLocationNameMultiMapIterator SNIterator;
10701  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10702 
10703  if(SNRange.first == SNRange.second) // i.e. location name not in map
10704  {
10705  Utilities->CallLogPop(1005);
10706  return(false); // should have been caught earlier but include for completeness
10707  }
10708  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10709  {
10710  if(SNIterator->second < 0)
10711  {
10712  continue; // exclude footcrossings
10713  }
10714  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
10715  if(InactiveElement.TrackType == Concourse)
10716  {
10717  continue; // only interested in locations where ActiveTrackElementName may be set
10718  }
10719  THVPair HVPair;
10720  HVPair.first = InactiveElement.HLoc;
10721  HVPair.second = InactiveElement.VLoc;
10722  if(TrackMap.find(HVPair) == TrackMap.end())
10723  {
10724  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
10725  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
10726  // then it won't be found in TrackMap but it's still legitimate.
10727  {
10728  continue;
10729  }
10730  else // for anything else throw the error
10731  {
10732  throw Exception
10733  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
10734  );
10735  }
10736  }
10737  int TVPos = TrackMap.find(HVPair)->second;
10738  if(TVPos != FirstNamedElementPos)
10739  {
10740  continue; // looking for an exact match
10741  }
10742  FirstNamedElement = TrackElementAt(567, TVPos);
10743  // first check linked on both sides, skip the check if not
10744  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10745  {
10746  continue;
10747  }
10748  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10749  // ActiveTrackElementNames are points and excluding trailing connections for points
10750  FirstNamedExitPos = 0;
10751  {
10752  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
10753  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10754  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10755  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10756  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10757  {
10758  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10759  {
10760  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
10761  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10762  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10763  // success, now check FirstNamedElement link not trailing points & if so all OK
10764  {
10765  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10766  {
10767  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10768  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10769  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10770  Utilities->CallLogPop(1006);
10771  return(true);
10772  }
10773  }
10774  }
10775  }
10776  }
10777  // failed, try link 1
10778  FirstNamedExitPos = 1;
10779  {
10780  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
10781  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10782  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10783  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10784  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10785  {
10786  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10787  {
10788  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
10789  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10790  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10791  // success, now check FirstNamedElement link not trailing points & if so all OK
10792  {
10793  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10794  {
10795  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10796  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10797  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10798  Utilities->CallLogPop(1007);
10799  return(true);
10800  }
10801  }
10802  }
10803  }
10804  }
10805  }
10806  Utilities->CallLogPop(1008);
10807  return(false);
10808 }
10809 
10810 // ---------------------------------------------------------------------------
10811 
10812 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
10813 {
10814  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
10815  TLocationNameMultiMapIterator SNIterator;
10816  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10817 
10818  if(SNRange.first != SNRange.second)
10819  {
10820  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10821  {
10822  if(SNIterator->second < 0)
10823  {
10824  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
10825  }
10826  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
10827  SNIterator->second).TrackType == NamedNonStationLocation))
10828  {
10829  Utilities->CallLogPop(1121);
10830  return(true);
10831  }
10832  }
10833  }
10834  Utilities->CallLogPop(848);
10835  return(false);
10836 }
10837 
10838 // ---------------------------------------------------------------------------
10839 
10840 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
10841 {
10842 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
10843  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
10844  "," + AnsiString(SpeedTag));
10845  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
10846  {
10847  Utilities->CallLogPop(949);
10848  return(false);
10849  }
10850  bool FoundFlag;
10851  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
10852 
10853  if(!FoundFlag)
10854  {
10855  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
10856  }
10857  TTrackElement IAElement;
10858 
10859  if(SpeedTag == 68) // top sig
10860  {
10861  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
10862  {
10863  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
10864  {
10865  IAElement = InactiveTrackElementAt(50, IMPair.first);
10866  }
10867  else
10868  {
10869  IAElement = InactiveTrackElementAt(51, IMPair.second);
10870  }
10871  if(IAElement.LocationName == "")
10872  {
10873 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
10874  SignalPlatformGraphic = RailGraphics->gl76Striped;
10875  }
10876  else
10877  {
10878 // SignalPlatformGraphic = RailGraphics->Plat68;
10879  SignalPlatformGraphic = RailGraphics->gl76;
10880  }
10881  Utilities->CallLogPop(950);
10882  return(true);
10883  }
10884  }
10885  else if(SpeedTag == 69) // bot sig
10886  {
10887  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
10888  {
10889  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
10890  {
10891  IAElement = InactiveTrackElementAt(77, IMPair.first);
10892  }
10893  else
10894  {
10895  IAElement = InactiveTrackElementAt(78, IMPair.second);
10896  }
10897  if(IAElement.LocationName == "")
10898  {
10899 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
10900  SignalPlatformGraphic = RailGraphics->bm77Striped;
10901  }
10902  else
10903  {
10904 // SignalPlatformGraphic = RailGraphics->Plat69;
10905  SignalPlatformGraphic = RailGraphics->bm77;
10906  }
10907  Utilities->CallLogPop(951);
10908  return(true);
10909  }
10910  }
10911  else if(SpeedTag == 70) // left sig
10912  {
10913  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
10914  {
10915  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
10916  {
10917  IAElement = InactiveTrackElementAt(55, IMPair.first);
10918  }
10919  else
10920  {
10921  IAElement = InactiveTrackElementAt(82, IMPair.second);
10922  }
10923  if(IAElement.LocationName == "")
10924  {
10925 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
10926  SignalPlatformGraphic = RailGraphics->bm78Striped;
10927  }
10928  else
10929  {
10930 // SignalPlatformGraphic = RailGraphics->Plat70;
10931  SignalPlatformGraphic = RailGraphics->bm78;
10932  }
10933  Utilities->CallLogPop(952);
10934  return(true);
10935  }
10936  }
10937  else if(SpeedTag == 71) // right sig
10938  {
10939  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
10940  {
10941  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
10942  {
10943  IAElement = InactiveTrackElementAt(85, IMPair.first);
10944  }
10945  else
10946  {
10947  IAElement = InactiveTrackElementAt(86, IMPair.second);
10948  }
10949  if(IAElement.LocationName == "")
10950  {
10951 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
10952  SignalPlatformGraphic = RailGraphics->gl79Striped;
10953  }
10954  else
10955  {
10956 // SignalPlatformGraphic = RailGraphics->Plat71;
10957  SignalPlatformGraphic = RailGraphics->gl79;
10958  }
10959  Utilities->CallLogPop(953);
10960  return(true);
10961  }
10962  }
10963  Utilities->CallLogPop(954);
10964  return(false);
10965 }
10966 
10967 // ---------------------------------------------------------------------------
10968 
10969 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
10970 // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
10971 // false if not, if NextPos == -1, or if only own train on the track
10972 {
10973  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
10974  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
10975  if(NextEntryPos < 0)
10976  {
10977  Utilities->CallLogPop(1348);
10978  return(false);
10979  }
10980  TTrackElement TrackElement = TrackElementAt(713, NextPos);
10981 
10982  if(TrackElement.TrackType != Bridge)
10983  {
10984  Utilities->CallLogPop(1349);
10985  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
10986  }
10987 // bridge if reach here
10988  if(NextEntryPos > 1)
10989  {
10990  Utilities->CallLogPop(1350);
10991  return ((TrackElement.TrainIDOnBridgeTrackPos23 > -1) && (TrackElement.TrainIDOnBridgeTrackPos23 != OwnTrainID));
10992  }
10993  else
10994  {
10995  Utilities->CallLogPop(1351);
10996  return ((TrackElement.TrainIDOnBridgeTrackPos01 > -1) && (TrackElement.TrainIDOnBridgeTrackPos01 != OwnTrainID));
10997  }
10998 }
10999 
11000 // ---------------------------------------------------------------------------
11001 
11003 {
11004  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
11005  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
11006  {
11007  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
11008  }
11009  Utilities->CallLogPop(1483);
11010  return(SelectVector.at(At));
11011 }
11012 
11013 // ---------------------------------------------------------------------------
11014 
11015 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
11016 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
11017 {
11018  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
11019  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
11020  bool FoundFlag = false;
11021  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
11022  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
11023 
11024  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
11025  Utilities->CallLogPop(1538);
11026  return(FoundFlag);
11027 }
11028 
11029 // ---------------------------------------------------------------------------
11030 
11031 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
11032 {
11033 // return true if find an inactive element called 'Name'
11034  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
11035  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
11036  bool FoundFlag = false;
11037 
11038  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11039  {
11040  if(InactiveTrackElementAt(158, x).LocationName == Name)
11041  {
11042  FoundFlag = true;
11043  int V = InactiveTrackElementAt(159, x).VLoc;
11044  int H = InactiveTrackElementAt(160, x).HLoc;
11045  if(V > VLocHi)
11046  {
11047  VLocHi = V;
11048  }
11049  if(V < VLocLo)
11050  {
11051  VLocLo = V;
11052  }
11053  if(H < HLoc)
11054  {
11055  HLoc = H;
11056  }
11057  }
11058  }
11059  if(FoundFlag)
11060  {
11061  VPosHi = 16 * VLocHi;
11062  VPosLo = 16 * VLocLo;
11063  HPos = 16 * HLoc;
11064  Utilities->CallLogPop(1562);
11065  return(true);
11066  }
11067  else
11068  {
11069  Utilities->CallLogPop(1563);
11070  return(false);
11071  }
11072 }
11073 
11074 // ---------------------------------------------------------------------------
11075 
11076 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
11077 {
11078 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
11079 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
11080  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
11081  AnsiString(EndTVPosition));
11082  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
11083  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
11084 
11085 // get H & V values for the element adjacent to Link[0] & Link[1]
11086  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
11087  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
11088  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
11089  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
11090 
11091 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
11092  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
11093  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
11094  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
11095  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
11096 
11097  if(Link0Squares <= Link1Squares)
11098  {
11099  Utilities->CallLogPop(1851);
11100  return(0);
11101  }
11102  else
11103  {
11104  Utilities->CallLogPop(1852);
11105  return(1);
11106  }
11107 }
11108 
11109 // ---------------------------------------------------------------------------
11110 
11111 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
11112 {
11113  // element can be points or any other type
11114  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
11115  AnsiString(LinkPos));
11116  Derail = false;
11117  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
11118 
11119  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
11120  {
11121  if(TE.Attribute == 0)
11122  {
11123  Utilities->CallLogPop(663);
11124  return(1); // Att == 0 & ExitPos == 1 represent straight
11125  }
11126  else
11127  {
11128  Utilities->CallLogPop(664);
11129  return(3); // Att == 1 & ExitPos == 3 represent diverging
11130  }
11131  }
11132  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
11133  {
11134  if((LinkPos == 1) && (TE.Attribute == 0))
11135  {
11136  Utilities->CallLogPop(665);
11137  return(0); // Att == 0 represents straight
11138  }
11139  else if(LinkPos == 1)
11140  {
11141  Derail = true;
11142  Utilities->CallLogPop(666);
11143  return(0);
11144  }
11145  else if((LinkPos == 3) && (TE.Attribute == 1))
11146  {
11147  Utilities->CallLogPop(667);
11148  return(0);
11149  }
11150  else if(LinkPos == 3)
11151  {
11152  Derail = true;
11153  Utilities->CallLogPop(668);
11154  return(0);
11155  }
11156  }
11157  else if(LinkPos == 0)
11158  {
11159  Utilities->CallLogPop(669);
11160  return(1);
11161  }
11162  else if(LinkPos == 1)
11163  {
11164  Utilities->CallLogPop(670);
11165  return(0);
11166  }
11167  else if(LinkPos == 2)
11168  {
11169  Utilities->CallLogPop(671);
11170  return(3);
11171  }
11172  else if(LinkPos == 3)
11173  {
11174  Utilities->CallLogPop(672);
11175  return(2);
11176  }
11177  throw Exception("Error, failure in GetExitPos"); // should never reach here
11178 }
11179 
11180 // ----------------------------------------------------------------------------
11181 
11183 {
11184  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
11185  LCVector.clear();
11186  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11187  {
11188  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
11189  {
11190  LCVector.push_back(x);
11191  }
11192  }
11193  Utilities->CallLogPop(1931);
11194  return;
11195 }
11196 
11197 // ---------------------------------------------------------------------------
11198 
11199 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
11200 /*
11201  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
11202  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
11203  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
11204  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
11205 */
11206 {
11207  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
11208  AnsiString(Link));
11209  bool FoundFlag;
11210 
11211  TrainID = -1;
11212  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
11213 
11214  if(!FoundFlag)
11215  {
11216  Utilities->CallLogPop(2001);
11217  return(false);
11218  }
11219  TTrackElement TE = TrackElementAt(882, VecPos);
11220 
11221  TrainID = TE.TrainIDOnElement;
11222  if(TE.TrackType == Bridge)
11223  {
11224  if(TE.TrainIDOnElement > -1)
11225  {
11226  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
11227  {
11228  TrainID = TE.TrainIDOnBridgeTrackPos01;
11229  }
11230  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
11231  {
11232  TrainID = TE.TrainIDOnBridgeTrackPos23;
11233  }
11234  else
11235  {
11236  TrainID = -1; // shouldn't ever reach here but be safe
11237  }
11238  }
11239  }
11240  if(TrainID == -1)
11241  {
11242  Utilities->CallLogPop(2002);
11243  return(false);
11244  }
11245 // now get the train
11246  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
11247 
11248  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
11249  {
11250  Utilities->CallLogPop(2003);
11251  return(true);
11252  }
11253  TrainID = -1;
11254  Utilities->CallLogPop(2004);
11255  return(false);
11256 }
11257 
11258 // ---------------------------------------------------------------------------
11259 
11260 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
11261 /* New at v1.2.0
11262  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
11263  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
11264  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11265  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11266  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
11267  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
11268  Each of these is examined in turn for each route element in the relevant position.
11269 */
11270 {
11271  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11272  "," + AnsiString(DiagonalLinkNumber));
11273  TrainID = -1;
11274  TPrefDirElement TempPrefDirElement;
11275  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
11276 
11277  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
11278  {
11279  Utilities->CallLogPop(2027);
11280  return(true);
11281  }
11282  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
11283  {
11284  Utilities->CallLogPop(2028);
11285  return(true);
11286  }
11287  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
11288  {
11289  Utilities->CallLogPop(2029);
11290  return(true);
11291  }
11292  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
11293  {
11294  Utilities->CallLogPop(2030);
11295  return(true);
11296  }
11297  Utilities->CallLogPop(2031);
11298  return(false);
11299 }
11300 
11301 // ---------------------------------------------------------------------------
11302 
11303 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
11304 {
11305  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
11306  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
11307  TUserGraphicItem UGI;
11308  AnsiString JustFileName = "";
11309 
11310  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
11311  {
11312  UGI = UserGraphicVectorAt(17, x);
11313  int LastDelim = UGI.FileName.LastDelimiter('\\');
11314  if(LastDelim == 0) // can't find it so skip this item
11315  {
11316  continue;
11317  }
11318  else
11319  {
11320  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
11321  }
11322  Utilities->SaveFileString(VecFile, JustFileName);
11323  Utilities->SaveFileInt(VecFile, UGI.HPos);
11324  Utilities->SaveFileInt(VecFile, UGI.VPos);
11325  }
11326  Utilities->CallLogPop(2178);
11327 }
11328 
11329 // ---------------------------------------------------------------------------
11330 
11331 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
11332 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
11333 {
11334  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
11335  int NumPlats = 0;
11336  TTrackElement TempElement;
11337  int TempInt;
11338 
11339  typedef std::list<int> TNamePosList;
11340  TNamePosList NamePosList;
11341  typedef TNamePosList::iterator TNPLIt;
11342  TNPLIt NPLIt;
11343  typedef std::list<int> TOnePlatList;
11344  TOnePlatList OnePlatList;
11345  typedef TOnePlatList::iterator TOPLIt;
11346  TOPLIt OPLIt;
11347 
11348  NamePosList.clear();
11349  OnePlatList.clear();
11350  for(unsigned int x = 0; x < TrackVector.size(); x++)
11351  {
11352  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
11353  {
11354  NamePosList.push_back(x);
11355  }
11356  }
11357  //NamePosList complete
11358 
11359  if(!NamePosList.empty()) //first value for the loop examination
11360  {
11361  OnePlatList.push_back(NamePosList.back());
11362  NamePosList.pop_back(); //erase from NPV as done with it here
11363  }
11364  while(!OnePlatList.empty()) //loop to examine all linked elements
11365  {
11366  TempInt = OnePlatList.front();
11367  TempElement = TrackElementAt(989, TempInt);
11368 
11369  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
11370  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
11371  {
11372  OnePlatList.push_back(TempElement.Conn[0]);
11373  NamePosList.erase(NPLIt);
11374  }
11375  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
11376  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
11377  {
11378  OnePlatList.push_back(TempElement.Conn[1]);
11379  NamePosList.erase(NPLIt);
11380  }
11381  //here when loaded any connecting links into OnePlatList, so can erase the front element
11382  OnePlatList.erase(OnePlatList.begin());
11383  if(OnePlatList.empty())
11384  {
11385  NumPlats++; //finished with current linked elements so can increment NumPlats
11386  if(!NamePosList.empty())
11387  {
11388  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
11389  NamePosList.pop_back(); //erase from NPV as done with it there
11390  }
11391  }
11392  }
11393  Utilities->CallLogPop(2218);
11394  return(NumPlats);
11395 }
11396 
11397 // ---------------------------------------------------------------------------
11398 // UserGraphic, PrefDir & Route functions
11399 // ---------------------------------------------------------------------------
11400 
11402 {
11403  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
11404  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
11405  {
11406  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
11407  }
11408  Utilities->CallLogPop(2194);
11409  return(UserGraphicVector.at(At));
11410 }
11411 
11412 // ---------------------------------------------------------------------------
11413 
11414 int TOnePrefDir::LastElementNumber(int Caller) const
11415 {
11416  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
11417  int RetVal = PrefDirVector.size() - 1;
11418 
11419  if(RetVal < 0)
11420  {
11421  throw Exception("Return value negative in call to LastElementNumber");
11422  }
11423  Utilities->CallLogPop(114);
11424  return(RetVal);
11425 }
11426 
11427 // ---------------------------------------------------------------------------
11429 {
11430  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
11431  if(PrefDirVector.empty())
11432  {
11433  throw Exception("PrefDirVector empty in call to LastElementPtr");
11434  }
11435  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
11436 
11437  Utilities->CallLogPop(115);
11438  return(RetIT);
11439 }
11440 
11441 // ---------------------------------------------------------------------------
11443 {
11444  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
11445  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11446  {
11447  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
11448  }
11449  Utilities->CallLogPop(116);
11450  return(PrefDirVector.at(At));
11451 }
11452 
11453 // ---------------------------------------------------------------------------
11455 {
11456  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
11457  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11458  {
11459  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
11460  " in GetModifiablePrefDirElementAt");
11461  }
11462  Utilities->CallLogPop(117);
11463  return(PrefDirVector.at(At));
11464 }
11465 
11466 // ---------------------------------------------------------------------------
11468 {
11469  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
11470  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11471  {
11472  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
11473  }
11474  Utilities->CallLogPop(118);
11475  return(SearchVector.at(At));
11476 }
11477 
11478 // ---------------------------------------------------------------------------
11480 {
11481  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
11482  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11483  {
11484  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
11485  }
11486  Utilities->CallLogPop(119);
11487  return(SearchVector.at(At));
11488 }
11489 
11490 // ---------------------------------------------------------------------------
11491 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
11492 /*
11493  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
11494  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
11495  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
11496  set in later functions.
11497 */
11498 {
11499  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11500  ClearPrefDir();
11501  int TrackVectorPosition;
11502  TTrackElement TrackElement;
11503 
11504  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11505  {
11506  Utilities->CallLogPop(126);
11507  return(false);
11508  }
11509 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
11510  if(TrackElement.TrackType == Points)
11511  {
11512  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
11513  //it isn't known which trailing edge is the required PrefDir - could use the straight as
11514  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
11515  //best to prevent it to avoid problems
11516  Utilities->CallLogPop(127);
11517  return false;
11518  }
11519 */
11520  TPrefDirElement PrefDirElement(TrackElement);
11521 
11522  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
11523  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
11524  StorePrefDirElement(1, PrefDirElement); // enter first element
11525 // Note that ELink not set even if a buffer or continuation - these set in
11526 // ConvertPrefDirSearchVector after 2nd element added
11527 
11528  Utilities->CallLogPop(128);
11529  return(true);
11530 }
11531 
11532 // ---------------------------------------------------------------------------
11533 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
11534 
11535 /*
11536  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
11537  Examine the last element in the PrefDirvector, if ELink not set (start element) do an immediate
11538  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
11539  with setting the PrefDir vector, & return true. Also set FinishElement if found element was a buffer or continuation,
11540  so that the calling function knows that the PrefDir is complete.
11541  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
11542  SearchForPrefDir to examine all branches. If succeed set PrefDirvector & finishelement as appropriate.
11543  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
11544  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
11545  ConvertPrefDirSearchVector to set PrefDirVector. Set FinishElement appropriately.
11546  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
11547  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
11548  find the required element return false. CheckCount is used to keep track of set values to allow check later.
11549 */
11550 
11551 {
11552  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11553  FinishElement = false;
11554  int TrackVectorPosition;
11555 
11556  TotalSearchCount = 0;
11557  TTrackElement TrackElement, TempTrackElement;
11558 
11559  if(PrefDirVector.size() == 0)
11560  {
11561  Utilities->CallLogPop(129);
11562  return(false);
11563  }
11564  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11565  {
11566  Utilities->CallLogPop(130);
11567  return(false);
11568  }
11569 // set the search limits using the last stored element in PrefDirVector as the start point
11570 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
11571 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
11572 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
11573 
11574  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
11575 
11576  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
11577  {
11578  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
11579  SearchLimitHighH = TrackElement.HLoc + 15;
11580  }
11581  else
11582  {
11583  SearchLimitLowH = TrackElement.HLoc - 15;
11584  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
11585  }
11586  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
11587  {
11588  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
11589  SearchLimitHighV = TrackElement.VLoc + 15;
11590  }
11591  else
11592  {
11593  SearchLimitLowV = TrackElement.VLoc - 15;
11594  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
11595  }
11596 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
11597  check & TotalSearchCounts check
11598  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
11599  {
11600  ShowMessage("Unable to reach the selected element - too far ahead");
11601  Utilities->CallLogPop(1692);
11602  return false;
11603  }
11604 */
11605 // get last PrefDir element
11606  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
11607  {
11608  // check if TrackElement adjacent to any of the 4 XLinkPos'
11609  for(int x = 0; x < 4; x++)
11610  {
11611  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
11612  {
11613  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
11614  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
11615  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
11616  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
11617  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
11618  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
11619  // shouldn't ever get it in a serious railway though.
11620 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
11621  }
11622  }
11623  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
11624  {
11625  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
11626  SearchVector.clear(); // use this & convert to set all PrefDir element values
11627  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
11628  {
11630  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11631  {
11632  FinishElement = true;
11633  }
11634  Utilities->CallLogPop(131);
11635  return(true);
11636  }
11637  } // not an adjacent element
11638 
11639  // now check each of the 4 possible XLinkPos values
11640  for(int x = 0; x < 4; x++)
11641  {
11642  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
11643  {
11644  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
11645  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
11646  SearchVector.clear();
11647  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
11648  {
11650  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11651  {
11652  FinishElement = true;
11653  }
11654  Utilities->CallLogPop(132);
11655  return(true);
11656  }
11657  }
11658  } // here if checked all possible exits without success
11659  ShowMessage(
11660  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11661  Utilities->CallLogPop(133);
11662  return(false);
11663  }
11664 // dealt above with LastPrefDirElement being the start element (which can be points)
11665 
11666  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
11667  .ELinkPos] == Lead)) // leading point
11668  {
11669  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
11670  {
11671  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
11672  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
11673  // can't be buffers or gap if points
11674  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
11675  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
11676  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
11677  SearchVector.clear();
11678  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
11679  {
11681  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11682  {
11683  FinishElement = true;
11684  }
11685  Utilities->CallLogPop(134);
11686  return(true);
11687  }
11688  }
11689  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
11690  {
11691  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
11692  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
11693  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
11694  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
11695  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
11696  SearchVector.clear();
11697  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
11698  {
11700  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11701  {
11702  FinishElement = true;
11703  }
11704  Utilities->CallLogPop(135);
11705  return(true);
11706  }
11707  }
11708 // above dealt with immediate finds for leading point,
11709 // now deal with ordinary searches for leading point
11710  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
11711  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
11712  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
11713  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
11714  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
11715  SearchVector.clear();
11716  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
11717  {
11719  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11720  {
11721  FinishElement = true;
11722  }
11723  Utilities->CallLogPop(136);
11724  return(true);
11725  }
11726  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
11727  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
11728  // note that CheckCount already increased to allow for XLinkPos & XLink
11729  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
11730  SearchVector.clear();
11731  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
11732  {
11734  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11735  {
11736  FinishElement = true;
11737  }
11738  Utilities->CallLogPop(137);
11739  return(true);
11740  }
11741 // here if failed to find match for leading point
11742  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
11743  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
11744  ShowMessage(
11745  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11746  Utilities->CallLogPop(138);
11747  return(false);
11748  }
11749 // leading point fully dealt with above
11750 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
11751 // separately as covered in ordinary search.
11752 
11753  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
11754  SearchVector.clear();
11755 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
11756  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
11757  {
11759  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11760  {
11761  FinishElement = true;
11762  }
11763  Utilities->CallLogPop(139);
11764  return(true);
11765  }
11766  ShowMessage(
11767  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11768  Utilities->CallLogPop(140);
11769  return(false); // failed to find required element
11770 }
11771 
11772 // ---------------------------------------------------------------------------
11773 
11774 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
11775 /*
11776  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
11777  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
11778  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
11779  Keep a count of entries in SearchVector during the current function call, so that this number can be
11780  erased for an unproductive branch search.
11781  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
11782  element. If so save it & return true. If not check if buffer, continuation, or earlier position
11783  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
11784  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
11785  If not any of above, store element in searchvector, set the new current element values from the
11786  SearchElement, then go back to the while loop for the next step in the search.
11787 */
11788 {
11789  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
11790  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
11791  int VectorCount = 0;
11792 
11793  while(true)
11794  {
11795  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
11796  {
11797  for(int x = 0; x < VectorCount; x++)
11798  {
11799  SearchVector.erase(SearchVector.end() - 1);
11800  }
11801  Utilities->CallLogPop(141);
11802  return(false);
11803  }
11804  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
11805  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
11806  TPrefDirElement SearchElement(NextTrackElement);
11807  SearchElement.TrackVectorPosition = NextPosition;
11808  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
11809  SearchElement.ELinkPos = NextELinkPos;
11810  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
11811  int NextXLinkPos;
11812  if(SearchElement.ELinkPos == 0)
11813  {
11814  NextXLinkPos = 1;
11815  }
11816  if(SearchElement.ELinkPos == 1)
11817  {
11818  NextXLinkPos = 0;
11819  }
11820  if(SearchElement.ELinkPos == 2)
11821  {
11822  NextXLinkPos = 3;
11823  }
11824  if(SearchElement.ELinkPos == 3)
11825  {
11826  NextXLinkPos = 2;
11827  }
11828  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
11829  {
11830  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
11831  // but may be buffers, continuation or gap
11832  SearchElement.XLinkPos = NextXLinkPos;
11833  }
11834 // can't set XLink or XLinkPos yet if the element is a leading point.
11835 // check if found it
11836  if(SearchElement.TrackVectorPosition == RequiredPosition)
11837  {
11838  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
11839  VectorCount++; // not really needed but include for tidyness
11840  TotalSearchCount++;
11841  Utilities->CallLogPop(142);
11842  return(true);
11843  }
11844 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
11845 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
11846 // at a time - drop this
11847 /*
11848  if(PrefDirVector.size() > 200)
11849  {
11850  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
11851  Utilities->CallLogPop(1419);
11852  return false;
11853  }
11854 */
11855 // check if a buffer or continuation
11856  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
11857  {
11858  for(int x = 0; x < VectorCount; x++)
11859  {
11860  SearchVector.erase(SearchVector.end() - 1);
11861  }
11862  Utilities->CallLogPop(143);
11863  return(false);
11864  }
11865 // check if reached an earlier position on search PrefDir with same entry value
11866  for(unsigned int x = 0; x < SearchVector.size(); x++)
11867  {
11868  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
11869  {
11870  for(int x = 0; x < VectorCount; x++)
11871  {
11872  SearchVector.erase(SearchVector.end() - 1);
11873  }
11874  Utilities->CallLogPop(144);
11875  return(false);
11876  }
11877  }
11878 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
11879 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
11880  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11881  {
11882  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
11883  {
11884  for(int x = 0; x < VectorCount; x++)
11885  {
11886  SearchVector.erase(SearchVector.end() - 1);
11887  }
11888  Utilities->CallLogPop(1417);
11889  return(false);
11890  }
11891  }
11892 
11893 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
11894 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
11895 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
11897  {
11898  for(int x = 0; x < VectorCount; x++)
11899  {
11900  SearchVector.erase(SearchVector.end() - 1);
11901  }
11902  Utilities->CallLogPop(1691);
11903  return(false);
11904  }
11905 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
11906  if(SearchVector.size() > 150)
11907  {
11908  for(int x = 0; x < VectorCount; x++)
11909  {
11910  SearchVector.erase(SearchVector.end() - 1);
11911  }
11912  Utilities->CallLogPop(1418);
11913  return(false);
11914  }
11915 // check if reached a leading point
11916  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
11917  {
11918 // push element with XLink set to position [1]
11919  SearchElement.XLink = SearchElement.Link[1];
11920  SearchElement.XLinkPos = 1;
11921  SearchVector.push_back(SearchElement);
11922  VectorCount++;
11923  TotalSearchCount++;
11924  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
11925  // Note that have to use a TTrackElement in the recursive search, so SearchElement
11926  // can't be used. NextTrackElement is the corresponding TTrackElement.
11927  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
11928  {
11929  Utilities->CallLogPop(145);
11930  return(true);
11931  }
11932  else
11933  {
11934 // remove leading point with XLinkPos [1]
11935  SearchVector.erase(SearchVector.end() - 1);
11936  VectorCount--;
11937 // push element with XLink set to position [3]
11938  SearchElement.XLink = SearchElement.Link[3];
11939  SearchElement.XLinkPos = 3;
11940  SearchVector.push_back(SearchElement);
11941  VectorCount++;
11942  TotalSearchCount++;
11943 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
11944  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
11945  {
11946  Utilities->CallLogPop(146);
11947  return(true);
11948  }
11949  else
11950  {
11951  for(int x = 0; x < VectorCount; x++)
11952  {
11953  SearchVector.erase(SearchVector.end() - 1);
11954  }
11955  Utilities->CallLogPop(147);
11956  return(false);
11957  }
11958  }
11959  } // if leading point
11960 
11961 // here if ordinary element, push it, inc vector & update CurrentTrackElement
11962 // ready for next element on PrefDir
11963  SearchVector.push_back(SearchElement);
11964  VectorCount++;
11965  TotalSearchCount++;
11966  XLinkPos = NextXLinkPos;
11967  CurrentTrackElement = SearchElement;
11968  } // while(true)
11969 }
11970 
11971 // ---------------------------------------------------------------------------
11972 
11974 /*
11975  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
11976  for each element on the search PrefDir, though if the last element is a leading point
11977  then the final XLink won't be set.
11978  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
11979  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
11980  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
11981 */
11982 {
11983  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
11984  if(SearchVector.size() == 0)
11985  {
11986  throw Exception("Error, SearchVector empty");
11987  }
11988 // get first SearchElement in order to set last PrefDirelement
11989  TPrefDirElement SearchElement = SearchVector.at(0);
11990 
11991 // set last PrefDir element XLink & ELink values if not already set
11992 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
11993  for(int x = 0; x < 4; x++)
11994  {
11995  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
11996  {
11997  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
11998  {
11999  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
12000  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
12001  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
12002  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
12003  }
12004  int ELinkPos;
12005  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
12006  {
12007  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
12008  }
12009  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
12010  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
12011  {
12012  ELinkPos = 0;
12013  }
12014  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
12015  {
12016  ELinkPos = 3;
12017  }
12018  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
12019  {
12020  ELinkPos = 2;
12021  }
12022  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
12023  {
12024  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
12025  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
12026  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
12027  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
12028  }
12029  break; // no point going any further
12030  }
12031  }
12032 // set EXNumber for last PrefDir element, unless already set
12033 // won't be set if was first element or a leading point
12034  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
12035  {
12036 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
12037  int EXArray[32][2] = {
12038  {4,6},{2,8}, //horizontal & vertical
12039  {2,4},{6,2},{8,6},{4,8}, //sharp curves
12040  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
12041  {1,9},{3,7} //forward & reverse diagonals
12042 */
12043 
12044  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
12045  {
12046  throw Exception("Error in EntryExitNumber 1");
12047  }
12048  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
12049  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
12050  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
12051  }
12052 // Last PrefDir element now complete
12053 
12054 // construct remaining PrefDir elements from searchvector
12055  for(unsigned int x = 0; x < SearchVector.size(); x++)
12056  {
12057  SearchElement = SearchVector.at(x);
12058  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
12059  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
12060  PrefDirElement.ELink = SearchElement.ELink;
12061  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
12062  PrefDirElement.XLink = SearchElement.XLink;
12063  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
12064 // if XLink & XLinkPos not set don't account for them in CheckCount
12065  if(PrefDirElement.XLink == -1)
12066  {
12067  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12068  }
12069  // & TrackVectorPosition
12070  else
12071  {
12072  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12073  }
12074  // XLink, XLinkPos, TrackVectorPosition
12075 
12076 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
12077  if(PrefDirElement.XLink != -1)
12078  {
12079  if(!(PrefDirElement.EntryExitNumber()))
12080  {
12081  throw Exception("Error in EntryExitNumber 2");
12082  }
12083  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
12084  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
12085  PrefDirElement.CheckCount++;
12086  // all values now incorporated if not a leading point
12087  }
12088 // store PrefDir element
12089  StorePrefDirElement(2, PrefDirElement);
12090  }
12091 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
12092  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
12093  {
12094  if(ValidatePrefDir(2))
12095  {
12096  ;
12097  } // error messages given within function
12098 
12099  }
12101 /* drop this, check dropped from search
12102  if(PrefDirVector.size() > 200)
12103  {
12104  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
12105  }
12106 */
12107  Utilities->CallLogPop(148);
12108 }
12109 
12110 // ---------------------------------------------------------------------------
12111 
12112 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
12113 /*
12114  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
12115  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
12116 */
12117 {
12118  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
12119  LeadingPoints = false;
12120  if(PrefDirVector.empty())
12121  {
12122  Utilities->CallLogPop(1786);
12123  return(false); // should never be empty but allow for it for safety
12124  }
12125  if(PrefDirVector.size() == 1)
12126  {
12127  Utilities->CallLogPop(149);
12128  return(false); // can't end if only one element
12129  }
12130 /*
12131  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
12132  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
12133  {
12134  Utilities->CallLogPop(150);
12135  return true;
12136  }
12137 */
12138 // allow for anything but leading points
12139  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
12140  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
12141  {
12142  Utilities->CallLogPop(1776);
12143  return(true);
12144  }
12145  else
12146  {
12147  LeadingPoints = true;
12148  Utilities->CallLogPop(151);
12149  return(false);
12150  }
12151 }
12152 
12153 // ---------------------------------------------------------------------------
12154 
12156 /*
12157  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
12158  and that every element is connected to the next element
12159 */
12160 {
12161  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
12162  int Position;
12163  AnsiString ErrorString;
12164  bool Error = false;
12165 
12166  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12167  {
12168  if(PrefDirVector.at(x).HLoc == -2000000000)
12169  {
12170  Error = true;
12171  ErrorString = "HLoc";
12172  Position = x;
12173  }
12174  if(PrefDirVector.at(x).VLoc == -2000000000)
12175  {
12176  Error = true;
12177  ErrorString = "VLoc";
12178  Position = x;
12179  }
12180  if(PrefDirVector.at(x).ELink == -1)
12181  {
12182  Error = true;
12183  ErrorString = "ELink";
12184  Position = x;
12185  }
12186  if(PrefDirVector.at(x).ELinkPos == -1)
12187  {
12188  Error = true;
12189  ErrorString = "ELinkPos";
12190  Position = x;
12191  }
12192  if(PrefDirVector.at(x).XLink == -1)
12193  {
12194  Error = true;
12195  ErrorString = "XLink";
12196  Position = x;
12197  }
12198  if(PrefDirVector.at(x).XLinkPos == -1)
12199  {
12200  Error = true;
12201  ErrorString = "XLinkPos";
12202  Position = x;
12203  }
12204  if(PrefDirVector.at(x).SpeedTag == 0)
12205  {
12206  Error = true;
12207  ErrorString = "Tag";
12208  Position = x;
12209  }
12210  if(PrefDirVector.at(x).TrackVectorPosition == -1)
12211  {
12212  Error = true;
12213  ErrorString = "TrackVectorPosition";
12214  Position = x;
12215  }
12216  if(PrefDirVector.at(x).EXNumber == -1)
12217  {
12218  Error = true;
12219  ErrorString = "EXNumber";
12220  Position = x;
12221  }
12222  if(PrefDirVector.at(x).CheckCount != 9)
12223  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
12224  {
12225  Error = true;
12226  ErrorString = "CheckCount";
12227  Position = x;
12228  }
12229 // extra checks
12230  if(PrefDirVector.at(x).EXGraphicPtr == 0)
12231  {
12232  Error = true;
12233  ErrorString = "EntryGraphicPtr";
12234  Position = x;
12235  }
12236  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
12237  {
12238  Error = true;
12239  ErrorString = "EntryDirectionGraphicPtr";
12240  Position = x;
12241  }
12242 // end of extra checks
12243  if(x > 0)
12244  {
12245  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
12246  {
12247  Error = true;
12248  ErrorString = "Last XLink not connected to this element";
12249  Position = x;
12250  }
12251  }
12252  }
12253  if(Error)
12254  {
12255  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
12256  }
12257  else
12258  {
12259  Utilities->CallLogPop(153);
12260  return(true);
12261  }
12262 }
12263 
12264 // ---------------------------------------------------------------------------
12265 
12266 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
12267 /*
12268  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
12269  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
12270  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
12271  or a leading point.
12272 */
12273 {
12274  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12275  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
12276  {
12277  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
12278  {
12279  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
12280  {
12281  ErasePrefDirElementAt(1, PrefDirVecPos);
12282  }
12283  if(PrefDirVector.size() == 0)
12284  {
12285  Utilities->CallLogPop(154);
12286  return(true);
12287  }
12288  if(PrefDirVector.size() == 1)
12289  {
12290  PrefDirVector.at(x - 1).ELinkPos = -1;
12291  PrefDirVector.at(x - 1).ELink = -1;
12292  PrefDirVector.at(x - 1).XLinkPos = -1;
12293  PrefDirVector.at(x - 1).XLink = -1;
12294  PrefDirVector.at(x - 1).EXNumber = -1;
12295  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12296  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12297  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
12298  Utilities->CallLogPop(155);
12299  return(true);
12300  }
12301  // here with truncate element not first element, so ELink & ELinkPos set
12302  // unset XLink & Pos if a leading point
12303  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
12304  {
12305  PrefDirVector.at(x - 1).XLinkPos = -1;
12306  PrefDirVector.at(x - 1).XLink = -1;
12307  PrefDirVector.at(x - 1).EXNumber = -1;
12308  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12309  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12310  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
12311  Utilities->CallLogPop(156);
12312  return(true);
12313  }
12314  Utilities->CallLogPop(157);
12315  return(true);
12316  }
12317  }
12318  Utilities->CallLogPop(158);
12319  return(false);
12320 }
12321 
12322 // ---------------------------------------------------------------------------
12323 
12324 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
12325 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
12326 /*
12327  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
12328  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
12329  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
12330  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
12331  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
12332  displayed.
12333 */
12334 {
12335  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
12336  AnsiString((short)BuildingPrefDir));
12337  int HPos, VPos;
12338 
12339  if(PrefDirSize() == 0)
12340  {
12341  Utilities->CallLogPop(159);
12342  return;
12343  }
12344  for(unsigned int x = 0; x < PrefDirSize(); x++)
12345  {
12346  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
12347 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
12348 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
12349 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
12350  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
12351  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
12352  // only the front half of which will be overplotted by the back of the train, then when the train is
12353  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
12354  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
12355  {
12356  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
12357  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
12358  {
12359  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12360  }
12361  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
12362  // Route, no direction if a single element
12363  {
12364  if(x == 0)
12365  {
12366  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12367  }
12368  if(x == (PrefDirSize() - 1))
12369  {
12370  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12371  }
12372  }
12373  }
12374  }
12375 
12376 // set start & end element colours if building a PrefDir
12377  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
12378  {
12379  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
12380  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
12381  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
12382  // set last element colour
12383  if(PrefDirSize() > 1)
12384  {
12385  unsigned int LatestPos = PrefDirSize() - 1;
12386  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
12387  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
12388  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
12389  }
12390  }
12391  Disp->Update();
12392  Utilities->CallLogPop(160);
12393 }
12394 
12395 // ---------------------------------------------------------------------------
12396 
12398 /*
12399  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
12400  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
12401 */
12402 {
12403  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
12404  if(PrefDirSize() == 0)
12405  {
12406  Utilities->CallLogPop(1547);
12407  return;
12408  }
12409  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12410  bool FoundFlag;
12412  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12413 
12414  while(MMIT != PrefDir4MultiMap.end())
12415  {
12416  H = MMIT->first.first;
12417  V = MMIT->first.second;
12418  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12419  // always found in order, any missing have PrefDirPosx == -1
12420  if(PrefDirPos0 > -1)
12421  {
12422  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12423  }
12424  if(PrefDirPos1 > -1)
12425  {
12426  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
12427  }
12428  if(PrefDirPos2 > -1)
12429  {
12430  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
12431  }
12432  if(PrefDirPos3 > -1)
12433  {
12434  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
12435  }
12436  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
12437  {
12438  // need to plot all 4 in order to obtain all the direction graphics
12439  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12440  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12441  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12442  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12443  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12444  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12445  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
12446  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
12447  MMIT++;
12448  MMIT++;
12449  MMIT++;
12450  MMIT++;
12451  }
12452  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12453  {
12454  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12455  {
12456  // 0 & 1 constitute the bidirectional PrefDir
12457  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
12458  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
12459  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12460  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12461  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12462  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12463  MMIT++;
12464  MMIT++;
12465  MMIT++;
12466  }
12467  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
12468  {
12469  // 0 & 2 constitute the bidirectional PrefDir
12470  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12471  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12472  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12473  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12474  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12475  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12476  MMIT++;
12477  MMIT++;
12478  MMIT++;
12479  }
12480  else
12481  {
12482  // 1 & 2 constitute the bidirectional PrefDir
12483  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12484  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12485  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12486  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12487  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12488  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12489  MMIT++;
12490  MMIT++;
12491  MMIT++;
12492  }
12493  }
12494  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12495  {
12496  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12497  {
12498  // 0 & 1 constitute the bidirectional PrefDir
12499  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12500  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12501  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12502  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12503  MMIT++;
12504  MMIT++;
12505  }
12506  else
12507  {
12508  // 2 unidirectional PrefDirs
12509  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12510  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12511  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12512  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12513  MMIT++;
12514  MMIT++;
12515  }
12516  }
12517  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
12518  {
12519  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12520  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12521  MMIT++;
12522  }
12523  }
12524  Disp->Update();
12525  Utilities->CallLogPop(1548);
12526 }
12527 
12528 // ---------------------------------------------------------------------------
12529 
12530 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
12531 {
12532  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
12533  int TempInt;
12534 
12535  ClearPrefDir();
12536  int NumberOfPrefDirElements = 0;
12537 
12538  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12539  for(int x = 0; x < NumberOfPrefDirElements; x++)
12540  {
12541  VecFile >> TempInt; // TrackVectorPosition
12542  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
12543  LoadPrefDirElement.TrackVectorPosition = TempInt;
12544  VecFile >> TempInt;
12545  LoadPrefDirElement.ELink = TempInt;
12546  VecFile >> TempInt;
12547  LoadPrefDirElement.ELinkPos = TempInt;
12548  VecFile >> TempInt;
12549  LoadPrefDirElement.XLink = TempInt;
12550  VecFile >> TempInt;
12551  LoadPrefDirElement.XLinkPos = TempInt;
12552  VecFile >> TempInt;
12553  LoadPrefDirElement.EXNumber = TempInt;
12554  VecFile >> TempInt;
12555  LoadPrefDirElement.CheckCount = TempInt;
12556  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12557  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12558  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12559  if(!(LoadPrefDirElement.IsARoute))
12560  {
12561  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12562  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12563  }
12564  else
12565  {
12566  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12567  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12568  LoadPrefDirElement.PrefDirRoute);
12569  }
12570  StorePrefDirElement(5, LoadPrefDirElement);
12571  Utilities->LoadFileString(VecFile); // marker
12572  }
12574  Utilities->CallLogPop(161);
12575 }
12576 
12577 // ---------------------------------------------------------------------------
12578 
12579 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
12580 {
12581  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
12582  int TempInt;
12583 
12584  ClearPrefDir();
12585  int NumberOfPrefDirElements = 0;
12586 
12587  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12588  for(int x = 0; x < NumberOfPrefDirElements; x++)
12589  {
12590  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
12591  VecFile >> TempInt; // TrackVectorPosition
12592  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
12593  LoadPrefDirElement.TrackVectorPosition = TempInt;
12594  VecFile >> TempInt;
12595  LoadPrefDirElement.ELink = TempInt;
12596  VecFile >> TempInt;
12597  LoadPrefDirElement.ELinkPos = TempInt;
12598  VecFile >> TempInt;
12599  LoadPrefDirElement.XLink = TempInt;
12600  VecFile >> TempInt;
12601  LoadPrefDirElement.XLinkPos = TempInt;
12602  VecFile >> TempInt;
12603  LoadPrefDirElement.EXNumber = TempInt;
12604  VecFile >> TempInt;
12605  LoadPrefDirElement.CheckCount = TempInt;
12606  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12607  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12608  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12609  if(!(LoadPrefDirElement.IsARoute))
12610  {
12611  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12612  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12613  }
12614  else
12615  {
12616  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12617  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12618  LoadPrefDirElement.PrefDirRoute);
12619  }
12620  StorePrefDirElement(0, LoadPrefDirElement);
12621  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
12622  }
12624  Utilities->CallLogPop(1509);
12625 }
12626 
12627 // ---------------------------------------------------------------------------
12628 
12629 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
12630 /*
12631  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
12632  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
12633 */
12634 {
12635  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
12636  int TempInt;
12637  int NumberOfPrefDirElements = 0;
12638 
12639  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12640  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
12641  {
12642  Utilities->CallLogPop(1152);
12643  return(false);
12644  }
12645  for(int x = 0; x < NumberOfPrefDirElements; x++)
12646  {
12647  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
12648  {
12649  Utilities->CallLogPop(1766);
12650  return(false);
12651  }
12652  VecFile >> TempInt;
12653  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
12654  {
12655  Utilities->CallLogPop(163);
12656  return(false);
12657  }
12658  VecFile >> TempInt;
12659  if((TempInt < -1) || (TempInt > 9)) // ELink
12660  {
12661  Utilities->CallLogPop(162);
12662  return(false);
12663  }
12664  VecFile >> TempInt;
12665  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
12666  {
12667  Utilities->CallLogPop(164);
12668  return(false);
12669  }
12670  VecFile >> TempInt;
12671  if((TempInt < -1) || (TempInt > 9)) // XLink
12672  {
12673  Utilities->CallLogPop(165);
12674  return(false);
12675  }
12676  VecFile >> TempInt;
12677  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
12678  {
12679  Utilities->CallLogPop(166);
12680  return(false);
12681  }
12682  VecFile >> TempInt;
12683  if((TempInt < -1) || (TempInt > 27)) // EXNumber
12684  {
12685  Utilities->CallLogPop(167);
12686  return(false);
12687  }
12688  VecFile >> TempInt;
12689  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
12690  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
12691  // ELinkPos, XLink, XLinkPos & EXNumber
12692  {
12693  Utilities->CallLogPop(168);
12694  return(false);
12695  }
12696  VecFile >> TempInt;
12697  if((TempInt != 0) && (TempInt != 1)) // RouteElement
12698  {
12699  Utilities->CallLogPop(1147);
12700  return(false);
12701  }
12702  VecFile >> TempInt;
12703  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
12704  {
12705  Utilities->CallLogPop(1510);
12706  return(false);
12707  }
12708  VecFile >> TempInt;
12709  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
12710  {
12711  Utilities->CallLogPop(1148);
12712  return(false);
12713  }
12714  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
12715  {
12716  Utilities->CallLogPop(1700);
12717  return(false);
12718  }
12719  }
12720  Utilities->CallLogPop(169);
12721  return(true);
12722 }
12723 
12724 // ---------------------------------------------------------------------------
12725 
12726 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
12727 {
12728  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
12729  int NumberOfPrefDirElements = PrefDirVector.size();
12730 
12731  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
12732  for(int y = 0; y < NumberOfPrefDirElements; y++)
12733  {
12734  VecFile << y << '\n'; // extra
12735  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
12736  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
12737  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
12738  VecFile << PrefDirVector.at(y).XLink << '\n';
12739  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
12740  VecFile << PrefDirVector.at(y).EXNumber << '\n';
12741  VecFile << PrefDirVector.at(y).CheckCount << '\n';
12742  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
12743  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
12744  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
12745  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
12746  {
12747  VecFile << "************" << '\0' << '\n'; // marker
12748  }
12749  else
12750  {
12751  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12752  }
12753  }
12754  Utilities->CallLogPop(170);
12755 }
12756 
12757 // ---------------------------------------------------------------------------
12758 
12759 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
12760 {
12761  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
12762  int NumberOfSearchElements = SearchVector.size();
12763 
12764  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
12765  for(int y = 0; y < NumberOfSearchElements; y++)
12766  {
12767  VecFile << y << '\n'; // extra
12768  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
12769  VecFile << SearchVector.at(y).ELink << '\n';
12770  VecFile << SearchVector.at(y).ELinkPos << '\n';
12771  VecFile << SearchVector.at(y).XLink << '\n';
12772  VecFile << SearchVector.at(y).XLinkPos << '\n';
12773  VecFile << SearchVector.at(y).EXNumber << '\n';
12774  VecFile << SearchVector.at(y).CheckCount << '\n';
12775  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
12776  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
12777  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
12778  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
12779  {
12780  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12781  }
12782  else
12783  {
12784  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12785  }
12786  }
12787  Utilities->CallLogPop(1847);
12788 }
12789 
12790 // ---------------------------------------------------------------------------
12791 
12792 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
12793 /*
12794  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
12795  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
12796 */
12797 {
12798  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
12799  AnsiString(VLoc));
12800  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
12801 
12802  if(VecPos > -1)
12803  {
12804  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
12805  }
12806  else
12807  {
12808  Utilities->CallLogPop(171);
12809  return;
12810  }
12811  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
12812  if(VecPos > -1)
12813  {
12814  ErasePrefDirElementAt(3, VecPos);
12815  }
12816  else
12817  {
12818  Utilities->CallLogPop(172);
12819  return;
12820  }
12821  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
12822  if(VecPos > -1)
12823  {
12824  ErasePrefDirElementAt(4, VecPos);
12825  }
12826  else
12827  {
12828  Utilities->CallLogPop(173);
12829  return;
12830  }
12831  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
12832  if(VecPos > -1)
12833  {
12834  ErasePrefDirElementAt(5, VecPos);
12835  }
12836  else
12837  {
12838  Utilities->CallLogPop(174);
12839  return;
12840  }
12841  Utilities->CallLogPop(175);
12842 }
12843 
12844 // ---------------------------------------------------------------------------
12845 /*
12846  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
12847  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
12848 
12849  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
12850  in their place so that existing linkages will be preserved. At this stage this function is called to remove
12851  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
12852  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
12853  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
12854  PrefDirVector to correspond to the new track layout.
12855 
12856  {
12857  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
12858  if(PrefDirSize() == 0)
12859  {
12860  Utilities->CallLogPop(176);
12861  return;
12862  }
12863  for(int x=(PrefDirVector.size()-1);x>=0;x--)
12864  {
12865  int TV = PrefDirVector.at(x).TrackVectorPosition;
12866  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
12867  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
12868  if(Track->BlankElementAt(0, TV))
12869  {
12870  ErasePrefDirElementAt(6, x);
12871  }
12872  //if was a blankelement at x then ConnELink and ConnXLink both -1
12873  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
12874  {
12875  ErasePrefDirElementAt(7, x);
12876  }
12877  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
12878  //needs to be erased once, but if don't use 'else' then will erase two elements
12879  //since 'x' will correspond to the element after the first erased element
12880  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
12881  {
12882  ErasePrefDirElementAt(8, x);
12883  }
12884  }
12885  Utilities->CallLogPop(177);
12886  }
12887 */
12888 // ---------------------------------------------------------------------------
12889 
12890 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
12891 /*
12892  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
12893  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
12894 */
12895 {
12896  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
12897  bool AlreadyPresent, FoundFlag;
12898  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12899 
12900  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
12901  {
12902  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
12903  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12904  AlreadyPresent = false;
12905  if(FoundFlag)
12906  {
12907  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
12908  {
12909  AlreadyPresent = true;
12910  }
12911  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
12912  {
12913  AlreadyPresent = true;
12914  }
12915  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
12916  {
12917  AlreadyPresent = true;
12918  }
12919  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
12920  {
12921  AlreadyPresent = true;
12922  }
12923  }
12924  if(!AlreadyPresent)
12925  {
12926  StorePrefDirElement(4, TempElement);
12927  }
12928  }
12930  Utilities->CallLogPop(178);
12931 }
12932 /* earlier brute force search
12933  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
12934  {
12935  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
12936  bool AlreadyPresent = false;
12937  for(unsigned int y = 0;y<PrefDirSize();y++)
12938  {
12939  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
12940  }
12941  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
12942  }
12943 */
12944 
12945 // ---------------------------------------------------------------------------
12946 
12948 /*
12949  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
12950  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
12951  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
12952  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
12953  positions are likely to have changed, so this function is called to reset all the necessary connections and
12954  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
12955  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
12956  shouldn't have changed.
12957 */
12958 {
12959  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
12960  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12961  {
12962  bool FoundFlag;
12963  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12964  if(FoundFlag)
12965  {
12966  PrefDirVector.at(x).TrackVectorPosition = VecPos;
12967  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
12968  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
12969  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
12970  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
12971  for(unsigned int z = 0; z < 4; z++)
12972  {
12973  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
12974  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
12975  }
12976  }
12977  else
12978  {
12979  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
12980  }
12981  }
12982  Utilities->CallLogPop(179);
12983 }
12984 
12985 // ---------------------------------------------------------------------------
12986 
12988 /*
12989  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
12990 */
12991 {
12992  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
12993  bool DiscrepancyFound = false;
12994 
12995  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12996  {
12997  bool FoundFlag;
12998  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12999  if(FoundFlag)
13000  {
13001  TPrefDirElement PE = PrefDirVector.at(x);
13002  if(PE.TrackVectorPosition != VecPos)
13003  {
13004  DiscrepancyFound = true;
13005  break;
13006  }
13007  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13008  {
13009  DiscrepancyFound = true;
13010  break;
13011  }
13012  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13013  {
13014  DiscrepancyFound = true;
13015  break;
13016  }
13017  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
13018  {
13019  DiscrepancyFound = true;
13020  break;
13021  }
13022  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
13023  {
13024  DiscrepancyFound = true;
13025  break;
13026  }
13027  }
13028  else
13029  {
13030  DiscrepancyFound = true;
13031  }
13032  }
13033  if(DiscrepancyFound)
13034  {
13035  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
13036  ClearPrefDir(); // also clears multimap
13037  }
13038  Utilities->CallLogPop(1436);
13039 }
13040 
13041 // ---------------------------------------------------------------------------
13042 
13044 /*
13045  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
13046  return true for OK
13047 */
13048 {
13049  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
13050  bool DiscrepancyFound = false;
13051 
13052  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13053  {
13054  bool FoundFlag;
13055  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13056  if(FoundFlag)
13057  {
13058  TPrefDirElement PE = PrefDirVector.at(x);
13059  if(PE.TrackVectorPosition != VecPos)
13060  {
13061  DiscrepancyFound = true;
13062  }
13063  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13064  {
13065  DiscrepancyFound = true;
13066  break;
13067  }
13068  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13069  {
13070  DiscrepancyFound = true;
13071  break;
13072  }
13073  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
13074  {
13075  DiscrepancyFound = true;
13076  break;
13077  }
13078  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
13079  {
13080  DiscrepancyFound = true;
13081  break;
13082  }
13083  }
13084  else
13085  {
13086  DiscrepancyFound = true;
13087  }
13088  }
13089  Utilities->CallLogPop(1512);
13090  return(!DiscrepancyFound);
13091 }
13092 
13093 // ---------------------------------------------------------------------------
13094 
13095 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
13096 /*
13097  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
13098  turn and for the overall sizes.
13099 */
13100 {
13101  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
13102  bool FoundFlag = false;
13103  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
13104 
13105  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
13106  {
13107  TPrefDirElement CheckElement = PrefDirVector.at(a);
13108  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
13109  if(!FoundFlag)
13110  {
13111  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
13112  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
13113  }
13114  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
13115  {
13116  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
13117  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
13118  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
13119  }
13120  }
13121  if(PrefDirVector.size() != PrefDir4MultiMap.size())
13122  {
13123  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
13124  + " Caller=" + (AnsiString)Caller);
13125  }
13126  Utilities->CallLogPop(180);
13127 }
13128 
13129 // ---------------------------------------------------------------------------
13130 
13131 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
13132  int &PrefDirPos3)
13133 /*
13134  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
13135  two tracks for 4-entry elements. This function retrieves all elements that are present at a given H & V
13136  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
13137  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
13138  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
13139 */
13140 {
13141  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
13142  AnsiString(VLoc));
13143  THVPair PrefDirMapKeyPair;
13144 
13145  PrefDirPos0 = -1;
13146  PrefDirPos1 = -1;
13147  PrefDirPos2 = -1;
13148  PrefDirPos3 = -1;
13149  FoundFlag = false;
13150  PrefDirMapKeyPair.first = HLoc;
13151  PrefDirMapKeyPair.second = VLoc;
13152  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13153 
13154  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
13155  if(ItPair.first == ItPair.second) //none found
13156  {
13157  Utilities->CallLogPop(181);
13158  return;
13159  }
13160  else
13161  {
13162  FoundFlag = true;
13163  PrefDirPos0 = ItPair.first->second;
13164  ItPair.first++;
13165  if(ItPair.first == ItPair.second)
13166  {
13167  Utilities->CallLogPop(182); //only one found
13168  return;
13169  }
13170  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13171  {
13172  PrefDirPos1 = ItPair.first->second;
13173  }
13174  ItPair.first++;
13175  if(ItPair.first == ItPair.second)
13176  {
13177  Utilities->CallLogPop(183); //2 found
13178  return;
13179  }
13180  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13181  {
13182  PrefDirPos2 = ItPair.first->second;
13183  }
13184  ItPair.first++;
13185  if(ItPair.first == ItPair.second)
13186  {
13187  Utilities->CallLogPop(184); //3 found
13188  return;
13189  }
13190  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13191  {
13192  PrefDirPos3 = ItPair.first->second; //4 found
13193  }
13194  }
13195  Utilities->CallLogPop(185);
13196 }
13197 
13198 // ---------------------------------------------------------------------------
13199 
13200 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13201 { //not used after modified the pref dir checking function at v2.13.0
13202  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
13203  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13204  try
13205  {
13206  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
13207  + "," + AnsiString(LinkNumberPos));
13208  bool FoundFlag;
13209  int PD0, PD1, PD2, PD3;
13210  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13211  {
13212  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13213  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13214  PD0, PD1, PD2, PD3);
13215  if(!FoundFlag)
13216  {
13217  Utilities->CallLogPop(2282);
13218  return(false);
13219  }
13220  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13221  {
13222  if(PD0 > -1)
13223  {
13224  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
13225  {
13226  LinkedPrefDirVectorNumber = PD0;
13227  Utilities->CallLogPop(2283);
13228  return(true);
13229  }
13230  }
13231  if(PD1 > -1)
13232  {
13233  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
13234  {
13235  LinkedPrefDirVectorNumber = PD1;
13236  Utilities->CallLogPop(2284);
13237  return(true);
13238  }
13239  }
13240  }
13241  if(PD0 > -1)
13242  {
13243  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
13244  {
13245  LinkedPrefDirVectorNumber = PD0;
13246  Utilities->CallLogPop(2285);
13247  return(true);
13248  }
13249  }
13250  if(PD1 > -1)
13251  {
13252  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
13253  {
13254  LinkedPrefDirVectorNumber = PD1;
13255  Utilities->CallLogPop(2286);
13256  return(true);
13257  }
13258  }
13259  if(PD2 > -1)
13260  {
13261  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
13262  {
13263  LinkedPrefDirVectorNumber = PD2;
13264  Utilities->CallLogPop(2287);
13265  return(true);
13266  }
13267  }
13268  if(PD3 > -1)
13269  {
13270  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
13271  {
13272  LinkedPrefDirVectorNumber = PD3;
13273  Utilities->CallLogPop(2288);
13274  return(true);
13275  }
13276  }
13277  LinkedPrefDirVectorNumber = -1;
13278  Utilities->CallLogPop(2289);
13279  return(false);
13280  }
13281  else //buffer or continuation, no link at position 0 but not a failure
13282  {
13283  LinkedPrefDirVectorNumber = -1;
13284  Utilities->CallLogPop(2290);
13285  return(true);
13286  }
13287  }
13288  catch(const Exception &e) //non error catch
13289  {
13290  LinkedPrefDirVectorNumber = -1;
13291  Utilities->CallLogPop(2291);
13292  return(false);
13293  }
13294 }
13295 
13296 // ---------------------------------------------------------------------------
13297 
13298 bool TOnePrefDir::FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13299 { //not used after modified the pref dir checking function at v2.13.0
13300  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if finds same direction pref dir with linked
13301  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13302  try
13303  {
13304  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingCompatiblePrefDir," + AnsiString(PrefDirVectorNumber)
13305  + "," + AnsiString(LinkNumberPos));
13306  bool FoundFlag;
13307  int PD0, PD1, PD2, PD3;
13308  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13309  {
13310  GetVectorPositionsFromPrefDir4MultiMap(31, Track->TrackElementAt(1463, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13311  Track->TrackElementAt(1464, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13312  PD0, PD1, PD2, PD3);
13313  if(!FoundFlag)
13314  {
13315  Utilities->CallLogPop(2468);
13316  return(false);
13317  }
13318  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13319  { //only PD0 or 1 will be set, else have track linking error that will be found earlier
13320  if(PD0 > -1)
13321  {
13322  if((PrefDirVector.at(PD0).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD0).XLink))
13323  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD0).ELink))))
13324  {
13325  LinkedPrefDirVectorNumber = PD0;
13326  Utilities->CallLogPop(2469);
13327  return(true);
13328  }
13329  }
13330  if(PD1 > -1)
13331  {
13332  if((PrefDirVector.at(PD1).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD1).XLink))
13333  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD1).ELink))))
13334  {
13335  LinkedPrefDirVectorNumber = PD1;
13336  Utilities->CallLogPop(2470);
13337  return(true);
13338  }
13339  }
13340  LinkedPrefDirVectorNumber = -1;
13341  Utilities->CallLogPop(2471);
13342  return(false);
13343  }
13344  if(PD0 > -1)
13345  {
13346  if((PrefDirVector.at(PD0).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD0).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13347  {
13348  LinkedPrefDirVectorNumber = PD0;
13349  Utilities->CallLogPop(2472);
13350  return(true);
13351  }
13352  }
13353  if(PD1 > -1)
13354  {
13355  if((PrefDirVector.at(PD1).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD1).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13356  {
13357  LinkedPrefDirVectorNumber = PD1;
13358  Utilities->CallLogPop(2473);
13359  return(true);
13360  }
13361  }
13362  if(PD2 > -1)
13363  {
13364  if((PrefDirVector.at(PD2).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD2).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13365  {
13366  LinkedPrefDirVectorNumber = PD2;
13367  Utilities->CallLogPop(2474);
13368  return(true);
13369  }
13370  }
13371  if(PD3 > -1)
13372  {
13373  if((PrefDirVector.at(PD3).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD3).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
13374  {
13375  LinkedPrefDirVectorNumber = PD3;
13376  Utilities->CallLogPop(2475);
13377  return(true);
13378  }
13379  }
13380  LinkedPrefDirVectorNumber = -1;
13381  Utilities->CallLogPop(2476);
13382  return(false);
13383  }
13384  else //buffer or continuation, no link at position 0 but not a failure
13385  {
13386  LinkedPrefDirVectorNumber = -1;
13387  Utilities->CallLogPop(2477);
13388  return(true);
13389  }
13390  }
13391  catch(const Exception &e) //non error catch
13392  {
13393  LinkedPrefDirVectorNumber = -1;
13394  Utilities->CallLogPop(2478);
13395  return(false);
13396  }
13397 }
13398 
13399 // ---------------------------------------------------------------------------
13400 
13402 {
13403  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
13404  bool FoundFlag; //not used
13405  int PD0, PD1, PD2, PD3;
13406  //recover all PDs at the H & V of PDPtr
13407  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
13408 
13409  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
13410  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
13411 
13412  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
13413  {
13414  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
13415  {
13416  Utilities->CallLogPop(2292);
13417  return(true);
13418  }
13419  }
13420  if(PD1 > -1)
13421  {
13422  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
13423  {
13424  Utilities->CallLogPop(2293);
13425  return(true);
13426  }
13427  }
13428  if(PD2 > -1)
13429  {
13430  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
13431  {
13432  Utilities->CallLogPop(2294);
13433  return(true);
13434  }
13435  }
13436  if(PD3 > -1)
13437  {
13438  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
13439  {
13440  Utilities->CallLogPop(2295);
13441  return(true);
13442  }
13443  }
13444  Utilities->CallLogPop(2296);
13445  return(false);
13446 }
13447 
13448 // ---------------------------------------------------------------------------
13449 
13450 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
13451 /*
13452  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
13453 */
13454 {
13455  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
13456  PrefDirVector.push_back(LoadPrefDirElement);
13457  THVPair PrefDir4MultiMapKeyPair;
13458  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
13459 
13460  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
13461  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
13462  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
13463  PrefDir4MultiMapEntry.second = LastElementNumber(68);
13464  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
13465 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
13466  Utilities->CallLogPop(186);
13467 }
13468 
13469 // ---------------------------------------------------------------------------
13470 
13471 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
13472 /*
13473  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
13474  4MultiMap if they are greater than the erased value.
13475 */
13476 {
13477  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
13478  bool FoundFlag;
13479 
13480  if(!PrefDirVector.empty())
13481  {
13482  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
13483  if(!FoundFlag)
13484  {
13485  throw Exception("Failed to find PrefDir4MultiMap erase element");
13486  }
13487  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
13488  PrefDir4MultiMap.erase(EraseIt);
13489  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
13491  }
13492  Utilities->CallLogPop(187);
13493 }
13494 
13495 // ---------------------------------------------------------------------------
13496 
13497 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
13498 /*
13499  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
13500  4MultiMap if they are greater than the erased value.
13501 */
13502 {
13503  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
13504  AnsiString(ErasedElementNumber));
13505  if(!PrefDir4MultiMap.empty())
13506  {
13507  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
13508  {
13509  if(MapPtr->second > ErasedElementNumber)
13510  {
13511  MapPtr->second--;
13512  }
13513  }
13514  }
13515  Utilities->CallLogPop(1450);
13516 }
13517 
13518 // ---------------------------------------------------------------------------
13519 
13520 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
13521 /*
13522  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
13523  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
13524  nothing is found this is an error but the error message is given in the calling function.
13525 */
13526 {
13527  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
13528  FoundFlag = false;
13529  if(PrefDirVectorPosition >= PrefDirVector.size())
13530  {
13531  throw Exception("PrefDirVectorPosition out of range");
13532  }
13533  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
13534  THVPair PrefDir4MultiMapKeyPair;
13535 
13536  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
13537  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
13538  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13539 
13540  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13541  if(ItPair.first == ItPair.second)
13542  {
13543  Utilities->CallLogPop(188);
13544  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
13545  }
13546  else
13547  {
13548  if(ItPair.first->second == PrefDirVectorPosition)
13549  {
13550  FoundFlag = true;
13551  Utilities->CallLogPop(189);
13552  return(ItPair.first);
13553  }
13554  ItPair.first++;
13555  if(ItPair.first == ItPair.second)
13556  {
13557  Utilities->CallLogPop(190);
13558  return(ItPair.first); // nothing found
13559  }
13560  if(ItPair.first->second == PrefDirVectorPosition)
13561  {
13562  FoundFlag = true;
13563  Utilities->CallLogPop(191);
13564  return(ItPair.first);
13565  }
13566  ItPair.first++;
13567  if(ItPair.first == ItPair.second)
13568  {
13569  Utilities->CallLogPop(192);
13570  return(ItPair.first); // nothing found
13571  }
13572  if(ItPair.first->second == PrefDirVectorPosition)
13573  {
13574  FoundFlag = true;
13575  Utilities->CallLogPop(193);
13576  return(ItPair.first);
13577  }
13578  ItPair.first++;
13579  if(ItPair.first == ItPair.second)
13580  {
13581  Utilities->CallLogPop(194);
13582  return(ItPair.first); // nothing found
13583  }
13584  if(ItPair.first->second == PrefDirVectorPosition)
13585  {
13586  FoundFlag = true;
13587  Utilities->CallLogPop(195);
13588  return(ItPair.first);
13589  }
13590  }
13591  Utilities->CallLogPop(196);
13592  return(ItPair.first); // nothing found
13593 }
13594 
13595 // ---------------------------------------------------------------------------
13596 
13597 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
13598 /*
13599  Although there may be up to four entries at one H & V position this function gets just one. It is
13600  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
13601  at H & V.
13602 */
13603 {
13604  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13605  THVPair PrefDir4MultiMapKeyPair;
13606 
13607  PrefDir4MultiMapKeyPair.first = HLoc;
13608  PrefDir4MultiMapKeyPair.second = VLoc;
13609  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13610 
13611  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13612  if(ItPair.first == ItPair.second) // nothing found
13613  {
13614  Utilities->CallLogPop(197);
13615  return(-1);
13616  }
13617  else
13618  {
13619  Utilities->CallLogPop(198);
13620  return(ItPair.first->second);
13621  }
13622 }
13623 
13624 // ---------------------------------------------------------------------------
13625 
13626 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
13627 {
13628  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
13629  bool ErasedFlag = false;
13630 
13631  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
13632  {
13633  if(PrefDirSize() == 0)
13634  {
13635  Utilities->CallLogPop(1511);
13636  return;
13637  }
13638  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
13639  {
13640  ErasedFlag = false;
13641  // use 'else' to ensure don't try to access an erased element
13642  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
13643  {
13644  ErasePrefDirElementAt(11, x);
13645  ErasedFlag = true;
13646  }
13647  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
13648  {
13649  ErasePrefDirElementAt(12, x);
13650  ErasedFlag = true;
13651  }
13652  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
13653  {
13654  ErasePrefDirElementAt(13, x);
13655  ErasedFlag = true;
13656  }
13657  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
13658  {
13659  ErasePrefDirElementAt(9, x);
13660  ErasedFlag = true;
13661  }
13662  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
13663  {
13664  ErasePrefDirElementAt(10, x);
13665  ErasedFlag = true;
13666  }
13667  if(!ErasedFlag)
13668  {
13669  // don't use 'else' here as may be more than one that need decrementing
13670  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
13671  {
13672  PrefDirVector.at(x).TrackVectorPosition--;
13673  }
13674  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
13675  {
13676  PrefDirVector.at(x).Conn[0]--;
13677  }
13678  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
13679  {
13680  PrefDirVector.at(x).Conn[1]--;
13681  }
13682  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
13683  {
13684  PrefDirVector.at(x).Conn[2]--;
13685  }
13686  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
13687  {
13688  PrefDirVector.at(x).Conn[3]--;
13689  }
13690  }
13691  }
13692  }
13693  Utilities->CallLogPop(1434);
13694 }
13695 
13696 // ---------------------------------------------------------------------------
13697 
13698 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
13699 {
13700  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
13701  OverallDistance = 0;
13702  OverallSpeedLimit = 0;
13703  LeadingPointsAtLastElement = false;
13704  if(PrefDirSize() == 0) // shouldn't be empty when this called
13705  {
13706  Utilities->CallLogPop(1491);
13707  return;
13708  }
13709  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
13710  {
13711  LeadingPointsAtLastElement = true;
13712  Utilities->CallLogPop(1492);
13713  return;
13714  }
13715  for(unsigned int x = 0; x < PrefDirSize(); x++)
13716  {
13717  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
13718  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
13719  {
13720  OverallDistance += PrefDirElement.Length23;
13721  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13722  {
13723  if(x == 0)
13724  {
13725  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
13726  }
13727  else
13728  {
13729  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
13730  {
13731  OverallSpeedLimit = -1;
13732  }
13733  }
13734  }
13735  }
13736  else
13737  {
13738  OverallDistance += PrefDirElement.Length01;
13739  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13740  {
13741  if(x == 0)
13742  {
13743  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
13744  }
13745  else
13746  {
13747  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
13748  {
13749  OverallSpeedLimit = -1;
13750  }
13751  }
13752  }
13753  }
13754  }
13755  Utilities->CallLogPop(1529);
13756 }
13757 
13758 // ---------------------------------------------------------------------------
13759 
13760 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
13761 {
13762  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
13763  if(PrefDirSize() == 0)
13764  {
13765  Utilities->CallLogPop(1564);
13766  return;
13767  }
13768  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13769  bool FoundFlag;
13771  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13772 
13773  while(MMIT != PrefDir4MultiMap.end())
13774  {
13775  HLoc = MMIT->first.first;
13776  VLoc = MMIT->first.second;
13777  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13778  H = HLoc - Track->GetHLocMin();
13779  V = VLoc - Track->GetVLocMin();
13780  // always found in order, any missing have PrefDirPosx == -1
13781  if(PrefDirPos0 > -1)
13782  {
13783  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13784  }
13785  if(PrefDirPos1 > -1)
13786  {
13787  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
13788  }
13789  if(PrefDirPos2 > -1)
13790  {
13791  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
13792  }
13793  if(PrefDirPos3 > -1)
13794  {
13795  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
13796  }
13797  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
13798  {
13799  // need to plot all 4 in order to obtain all the direction graphics
13800  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13801  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13802  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13803  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13804  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13805  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13806  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
13807  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
13808  MMIT++;
13809  MMIT++;
13810  MMIT++;
13811  MMIT++;
13812  }
13813  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13814  {
13815  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13816  {
13817  // 0 & 1 constitute the bidirectional PrefDir
13818  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13819  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13820  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13821  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13822  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
13823  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
13824  MMIT++;
13825  MMIT++;
13826  MMIT++;
13827  }
13828  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
13829  {
13830  // 0 & 2 constitute the bidirectional PrefDir
13831  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13832  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13833  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13834  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13835  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13836  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13837  MMIT++;
13838  MMIT++;
13839  MMIT++;
13840  }
13841  else
13842  {
13843  // 1 & 2 constitute the bidirectional PrefDir
13844  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13845  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13846  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13847  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13848  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13849  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13850  MMIT++;
13851  MMIT++;
13852  MMIT++;
13853  }
13854  }
13855  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13856  {
13857  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13858  {
13859  // 0 & 1 constitute the bidirectional PrefDir
13860  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13861  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13862  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13863  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13864  MMIT++;
13865  MMIT++;
13866  }
13867  else
13868  {
13869  // 2 unidirectional PrefDirs
13870  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13871  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13872  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13873  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13874  MMIT++;
13875  MMIT++;
13876  }
13877  }
13878  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
13879  {
13880  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13881  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13882  MMIT++;
13883  }
13884  }
13885  Utilities->CallLogPop(1565);
13886 }
13887 
13888 // ---------------------------------------------------------------------------
13889 
13890 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
13891 /*
13892  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
13893  level crossing, signals with wrong direction set, or buffers.
13894 */
13895 {
13896  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
13897  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13898  bool FoundFlag;
13900  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13901 
13902  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
13903  ElementIn.VLoc)))
13904  {
13905  Utilities->CallLogPop(1982);
13906  return(false);
13907  }
13908  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at exit end
13909  {
13910  Utilities->CallLogPop(1983);
13911  return(false);
13912  }
13913  if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal))
13914  {
13915  Utilities->CallLogPop(1995);
13916  return(false);
13917  }
13918 // Now check that there is only a single prefdir set
13919  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13920 // always found in order, any missing have PrefDirPosx == -1
13921  if(PrefDirPos0 > -1)
13922  {
13923  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13924  }
13925  if(PrefDirPos1 > -1)
13926  {
13927  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
13928  }
13929  if(PrefDirPos2 > -1)
13930  {
13931  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
13932  }
13933  if(PrefDirPos3 > -1)
13934  {
13935  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
13936  }
13937  if(PrefDirPos3 > -1) // 4 found, all bidirectional
13938  {
13939  Utilities->CallLogPop(1984);
13940  return(false);
13941  }
13942  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13943  {
13944  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
13945  {
13946  Utilities->CallLogPop(1985);
13947  return(false);
13948  }
13949  else
13950  {
13951  Utilities->CallLogPop(1986);
13952  return(true);
13953  }
13954  }
13955  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13956  {
13957  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
13958  {
13959  Utilities->CallLogPop(1987);
13960  return(false);
13961  }
13962  else
13963  {
13964  Utilities->CallLogPop(1988);
13965  return(true);
13966  }
13967  }
13968  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
13969  {
13970  if(PrefDirElement0.XLinkPos == EntryPos)
13971  {
13972  Utilities->CallLogPop(1989);
13973  return(false);
13974  }
13975  else
13976  {
13977  Utilities->CallLogPop(1990);
13978  return(true);
13979  }
13980  }
13981  else
13982  {
13983  Utilities->CallLogPop(1991);
13984  return(false); // none found
13985  }
13986 }
13987 
13988 // ---------------------------------------------------------------------------
13989 
13991 {
13992 /* //Added at v2.1.0
13993  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
13994  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
13995  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
13996  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
13997  and can be modelled better anyway.
13998 
13999  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
14000  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
14001  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14002  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14003  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14004  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14005 */
14006  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
14007  ElementIn.VLoc + "," + XLink);
14008  int TrackVecPos;
14009  bool TrackFoundFlag;
14010  TTrackElement TempTrackElement;
14011 
14012  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
14013  {
14014  Utilities->CallLogPop(2047);
14015  return(false);
14016  }
14017 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14018  if(XLink == 1)
14019  {
14020  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14021  if(TrackFoundFlag)
14022  {
14023  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
14024  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14025  {
14026  Utilities->CallLogPop(2048);
14027  return(true);
14028  }
14029  }
14030  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14031  if(TrackFoundFlag)
14032  {
14033  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
14034  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14035  {
14036  Utilities->CallLogPop(2049);
14037  return(true);
14038  }
14039  }
14040  }
14041 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14042  if(XLink == 3)
14043  {
14044  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14045  if(TrackFoundFlag)
14046  {
14047  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
14048  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14049  {
14050  Utilities->CallLogPop(2050);
14051  return(true);
14052  }
14053  }
14054  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14055  if(TrackFoundFlag)
14056  {
14057  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
14058  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14059  {
14060  Utilities->CallLogPop(2051);
14061  return(true);
14062  }
14063  }
14064  }
14065 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14066  if(XLink == 7)
14067  {
14068  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14069  if(TrackFoundFlag)
14070  {
14071  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
14072  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14073  {
14074  Utilities->CallLogPop(2052);
14075  return(true);
14076  }
14077  }
14078  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14079  if(TrackFoundFlag)
14080  {
14081  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
14082  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14083  {
14084  Utilities->CallLogPop(2053);
14085  return(true);
14086  }
14087  }
14088  }
14089 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14090  if(XLink == 9)
14091  {
14092  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14093  if(TrackFoundFlag)
14094  {
14095  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
14096  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14097  {
14098  Utilities->CallLogPop(2054);
14099  return(true);
14100  }
14101  }
14102  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14103  if(TrackFoundFlag)
14104  {
14105  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
14106  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14107  {
14108  Utilities->CallLogPop(2055);
14109  return(true);
14110  }
14111  }
14112  }
14113  Utilities->CallLogPop(2056);
14114  return(false);
14115 }
14116 
14117 // ---------------------------------------------------------------------------
14118 
14119 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
14120 {
14121 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
14122  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
14123  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
14124  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
14125  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
14126 */
14127  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
14129  bool FoundFlag, ContFlag, FoundElements = false;
14130  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14131  TPrefDirElement NextElement;
14132 
14133  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
14134  {
14135  LastIteratorValue++;
14136  ContFlag = false;
14137  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
14138  {
14139  continue;
14140  }
14141  if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal))
14142  {
14143  continue;
14144  }
14145 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
14146  // found a potential route start point
14147  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
14148  {
14149  continue;
14150  }
14151  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
14152  {
14153  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
14154  if(PDVIt->TrackType == Continuation)
14155  {
14156  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
14157  {
14158  continue;
14159  }
14160  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
14161  {
14162  continue;
14163  }
14164  }
14165  StartElement = *PDVIt;
14166 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
14167  // diverging track on which there was no pref dir. See below for 2 required changes.
14168  }
14169  else
14170  {
14171  continue;
14172  }
14173  // now track along until find a signal or continuation, checking validity for each element
14174  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
14175  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
14176  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14177  if(PrefDirPos0 == -1) // no continuing prefdir
14178  {
14179  continue;
14180  }
14181  bool NextElementFoundFlag = false;
14182  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14183  {
14184  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
14185  NextElementFoundFlag = true;
14186  }
14187  if(PrefDirPos1 > -1)
14188  {
14189  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14190  {
14191  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
14192  NextElementFoundFlag = true;
14193  }
14194  }
14195  if(PrefDirPos2 > -1)
14196  {
14197  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14198  {
14199  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
14200  NextElementFoundFlag = true;
14201  }
14202  }
14203  if(PrefDirPos3 > -1)
14204  {
14205  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14206  {
14207  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
14208  NextElementFoundFlag = true;
14209  }
14210  }
14211  if(!NextElementFoundFlag)
14212  {
14213  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14214 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
14215  }
14216  while(true)
14217  {
14218  // check validity
14219  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
14220  {
14221  ContFlag = true;
14222  break;
14223  }
14224  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
14225  {
14226  ContFlag = true;
14227  break;
14228  }
14229  // check if in a route, providing not a signal, as a signal might be at the start of a route
14230  if(NextElement.TrackType != SignalPost)
14231  {
14232  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
14233  {
14234  ContFlag = true;
14235  break;
14236  }
14237  }
14238  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
14239  // can't be a gound signal as would have failed the validity test
14240  {
14241  EndElement = NextElement;
14242  break;
14243  }
14244  // get the next element in the sequence
14245  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
14246  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
14247  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14248  if(PrefDirPos0 == -1) // no continuing prefdir
14249  {
14250  ContFlag = true;
14251  break;
14252  }
14253  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14254  {
14255  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
14256  continue;
14257  }
14258  if(PrefDirPos1 > -1)
14259  {
14260  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14261  {
14262  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
14263  continue;
14264  }
14265  }
14266  if(PrefDirPos2 > -1)
14267  {
14268  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14269  {
14270  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
14271  continue;
14272  }
14273  }
14274  if(PrefDirPos3 > -1)
14275  {
14276  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14277  {
14278  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
14279  continue;
14280  }
14281  }
14282  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
14283  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
14284  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
14285  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
14286  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
14287  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
14288  {
14289  ContFlag = true;
14290  break;
14291  }
14292  else
14293  {
14294  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14295  // could drop the bridge test but keep it to show the change history
14296  break;
14297 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
14298  }
14299  }
14300  if(ContFlag)
14301  {
14302  continue;
14303  }
14304  // else have start and end elements set & all elements valid, so set up the route segment
14305  FoundElements = true;
14306  break;
14307  }
14308  if(FoundElements)
14309  {
14310  Utilities->CallLogPop(1992);
14311  return(true);
14312  }
14313  else
14314  {
14315  Utilities->CallLogPop(1993);
14316  return(false);
14317  }
14318 }
14319 
14320 // ---------------------------------------------------------------------------
14321 // TOneRoute
14322 // ---------------------------------------------------------------------------
14323 
14324 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
14325 {
14326 /* General:
14327  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
14328  containing all the new elements to form the route. When complete, the SearchVector is converted into route
14329  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
14330  route will use automatic signals or not.
14331  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
14332  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
14333  elements, so additional work is needed to complete all their members before they are ready for conversion into
14334  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
14335  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
14336  ConvertAndAdd.......
14337 */
14338  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
14339  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
14340  ClearRoute();
14341  int TrackVectorPosition;
14342  TTrackElement TrackElement;
14343  TPrefDirElement FirstElement, LastElement;
14344 
14345  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
14346  {
14347  Utilities->CallLogPop(199);
14348  return(false);
14349  }
14350  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
14351  {
14352  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
14353  Utilities->CallLogPop(1996);
14354  return(false);
14355  }
14356  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14357  {
14358  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
14359  Utilities->CallLogPop(200);
14360  return(false);
14361  }
14362  if(Track->IsLCAtHV(18, HLoc, VLoc))
14363  {
14364  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
14365  Utilities->CallLogPop(1909);
14366  return(false);
14367  }
14368 // check if selected a train & disallow if so
14369  if(TrackElement.TrainIDOnElement > -1)
14370  {
14371  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
14372  Utilities->CallLogPop(202);
14373  return(false);
14374  }
14375 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
14376  TPrefDirElement PrefDirElement;
14377  int LockedVectorNumber;
14378 
14379  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
14380  {
14381  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
14382  Utilities->CallLogPop(203);
14383  return(false);
14384  }
14385  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
14386  {
14387  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
14388  Utilities->CallLogPop(204);
14389  return(false);
14390  }
14392  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
14393 // signal in an autosig route & follow with a non-autosig route
14394 
14395  TPrefDirElement BlankElement;
14396 
14397  StartElement1 = BlankElement;
14398  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
14399 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
14400  bool InPrefDirFlag = false;
14401 
14402  bool FoundFlag;
14403  int PrefDirPos0 = -1;
14404  int PrefDirPos1 = -1;
14405  int PrefDirPos2 = -1;
14406  int PrefDirPos3 = -1;
14407 
14409  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14410  int PrefDirVecPos[4] =
14411  {
14412  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14413  };
14414 
14415  for(int x = 0; x < 4; x++)
14416  {
14417  int b = PrefDirVecPos[x];
14418  if(b > -1)
14419  {
14420  // only allow the appropriate exit route to be searched
14421  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
14422  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
14423  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
14424  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
14425  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
14426  {
14427  InPrefDirFlag = true;
14428  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
14429  if(AutoSigsFlag)
14430  {
14431  StartElement1.AutoSignals = true;
14432  }
14433  StartElement1.PrefDirRoute = true;
14434  }
14435  }
14436  }
14437 
14438  if(!InPrefDirFlag)
14439  {
14441  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14442  Utilities->CallLogPop(205);
14443  return(false);
14444  }
14445 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
14447  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14448 
14449  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
14450  {
14451  throw Exception("Selection in two routes - should never happen!");
14452  }
14453  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
14454  {
14455  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
14456  {
14457  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
14458  Utilities->CallLogPop(206);
14459  return(false);
14460  }
14461  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
14462  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
14463  {
14464  TrainController->StopTTClockMessage(14, "No forward connection from this position");
14465  Utilities->CallLogPop(207);
14466  return(false);
14467  }
14468  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
14469  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
14470  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14471  {
14472  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
14473  Utilities->CallLogPop(208);
14474  return(false);
14475  }
14476  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
14478  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
14479  if(AutoSigsFlag)
14480  {
14481  StartElement1.AutoSignals = true;
14482  }
14483  StartElement1.PrefDirRoute = true;
14485  Utilities->CallLogPop(209);
14486  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
14487  }
14488 
14489  else // no route started
14490  {
14491 // check if selected position is adjacent to start or end of an existing route and disallow
14492  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14493  {
14494  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
14495  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
14496  {
14497  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
14498  Utilities->CallLogPop(210);
14499  return(false);
14500  }
14501  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
14502  {
14503  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
14504  Utilities->CallLogPop(211);
14505  return(false);
14506  }
14507  }
14508 
14509 // check if it's adjacent to end of an an existing route,
14510  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14511  {
14513  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
14514  {
14515  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
14516  Utilities->CallLogPop(212);
14517  return(false);
14518  }
14519  }
14520  SearchVector.push_back(StartElement1);
14521  Utilities->CallLogPop(213);
14522  return(true);
14523  }
14524 }
14525 
14526 // ---------------------------------------------------------------------------
14527 
14528 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
14529  IDInt &ReqPosRouteID, bool &PointsChanged)
14530 
14531 /*
14532  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
14533 
14534  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
14535  this being set to -1 for not used.
14536  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
14537  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
14538  Check correct type of element - signal/buffers/continuation.
14539  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
14540  EndElement2 corresponding to the 2 possible PrefDir elements).
14541  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
14542  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
14543  linked forward to another route.
14544  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
14545  for same position as start should cover this)
14546 
14547  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
14548  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
14549  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
14550  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
14551  If the search fails then return false.
14552  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
14553  in the SearchVector to ensure it's entered as part of the new route.
14554  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
14555  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
14556  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
14557  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
14558  so return false, with an appropriate message if ConsecSignalsRoute set.
14559 */
14560 
14561 {
14562  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
14563  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
14564  int EndPosition; // the position selected
14565 
14566  Track->LCFoundInAutoSigsRoute = false;
14568  TotalSearchCount = 0;
14569  ReqPosRouteID = IDInt(-1); // default value for not used
14570  TTrackElement TrackElement;
14571  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
14572  // given element as can't select 2-track elements
14573  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14574  {
14575  Utilities->CallLogPop(214);
14576  return(false);
14577  }
14578  if(Track->IsLCAtHV(19, HLoc, VLoc))
14579  {
14580  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
14581  Utilities->CallLogPop(1908);
14582  return(false);
14583  }
14584 // cancel selection if on original start element
14585  if(EndPosition == StartRoutePosition)
14586  {
14587  Utilities->CallLogPop(215);
14588  return(false);
14589  }
14590  if(AutoSigsFlag)
14591  {
14592  if(TrackElement.TrackType == Buffers)
14593  {
14594  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
14595  Utilities->CallLogPop(216);
14596  return(false);
14597  }
14598  }
14599  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14600  {
14601  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
14602  Utilities->CallLogPop(217);
14603  return(false);
14604  }
14605 // check if train on element
14606  if(TrackElement.TrainIDOnElement > -1)
14607  {
14608  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
14609  Utilities->CallLogPop(219);
14610  return(false);
14611  }
14612 // disallow if not in EveryPrefDir & set EndElement(s)
14613  bool InPrefDirFlag = false;
14614 
14615  bool FoundFlag;
14616  int PrefDirPos0 = -1;
14617  int PrefDirPos1 = -1;
14618  int PrefDirPos2 = -1;
14619  int PrefDirPos3 = -1;
14620 
14621  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
14622  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14623  int PrefDirVecPos[4] =
14624  {
14625  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14626  };
14627 
14628  for(int x = 0; x < 4; x++)
14629  {
14630  int b = PrefDirVecPos[x];
14631  if(b > -1)
14632  {
14633  InPrefDirFlag = true;
14634  if(EndElement1.TrackVectorPosition == -1)
14635  {
14636  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
14637  }
14638  else
14639  {
14640  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
14641  }
14642  }
14643  }
14644  if(!InPrefDirFlag)
14645  {
14647  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14648  Utilities->CallLogPop(220);
14649  return(false);
14650  }
14651 // check if in an existing route - can't be a bridge so can use a simple 'find'
14652 // bool InRoute = false;
14654  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14655 
14656  if(RoutePair.first > -1)
14657  {
14658  if(RoutePair.second != 0) // not first element in existing route so no good
14659  {
14660  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
14661  Utilities->CallLogPop(221);
14662  return(false);
14663  }
14664  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
14665 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14666  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
14667  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14668  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
14669  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14670  {
14671  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
14672  Utilities->CallLogPop(222);
14673  return(false);
14674  }
14675  EndElement1 = RouteElement;
14676  EndElement2 = BlankElement; // only need the route element
14677  EndPosition = EndElement1.TrackVectorPosition;
14678  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
14679  }
14680 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14681 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14682 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14683 
14684  if(EndElement1.HLoc >= StartElement1.HLoc)
14685  {
14687  SearchLimitHighH = EndElement1.HLoc + 15;
14688  }
14689  else
14690  {
14691  SearchLimitLowH = EndElement1.HLoc - 15;
14693  }
14694  if(EndElement1.VLoc >= StartElement1.VLoc)
14695  {
14697  SearchLimitHighV = EndElement1.VLoc + 15;
14698  }
14699  else
14700  {
14701  SearchLimitLowV = EndElement1.VLoc - 15;
14703  }
14704 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14705  check & TotalSearchCounts check
14706  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14707  {
14708  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
14709  Utilities->CallLogPop(1693);
14710  return false;
14711  }
14712 */
14713 // check if adjacent to start and disallow
14714  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14715  {
14717  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
14718 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
14719 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
14720  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14721  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14722  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
14723  {
14724  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
14725  Utilities->CallLogPop(223);
14726  return(false);
14727  }
14728 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
14729 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
14730  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
14731  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14732  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
14733  {
14734  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
14735  Utilities->CallLogPop(224);
14736  return(false);
14737  }
14738 // check if adjacent to end of a route & disallow
14740  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
14741  {
14742  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
14743  Utilities->CallLogPop(225);
14744  return(false);
14745  }
14746  }
14747 
14748 // check for same route as start element
14750  {
14751  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
14752  Utilities->CallLogPop(226);
14753  return(false);
14754  }
14755 // check for a looping route
14756  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
14757  {
14759  {
14760  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
14761  Utilities->CallLogPop(1844);
14762  return(false);
14763  }
14764  }
14765 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
14766 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
14767 // and don't want to add it again
14768  if(StartSelectionRouteID > -1)
14769  {
14770  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14771  AutoSigsFlag))
14772  {
14773  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
14774  if(PointsToBeChanged(5))
14775  {
14776  PointsChanged = true;
14777  }
14778  Utilities->CallLogPop(227);
14779  return(true);
14780  }
14781  else if(!Track->SuppressRouteFailMessage)
14782  {
14783  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
14785  Utilities->CallLogPop(228);
14786  return(false);
14787  }
14788  }
14789  else
14790  {
14791 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
14792 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
14793 
14794 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
14795 // note that a blank element will have XLinkPos set to -1
14796  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
14797  {
14798  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14799  AutoSigsFlag))
14800  {
14801  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
14802  if(PointsToBeChanged(6))
14803  {
14804  PointsChanged = true;
14805  }
14806  Utilities->CallLogPop(229);
14807  return(true);
14808  }
14809  else
14810  {
14812  {
14814  }
14815  Utilities->CallLogPop(230);
14816  return(false);
14817  }
14818  }
14819  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
14820  {
14821  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14822  AutoSigsFlag))
14823  {
14824  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
14825  if(PointsToBeChanged(7))
14826  {
14827  PointsChanged = true;
14828  }
14829  Utilities->CallLogPop(231);
14830  return(true);
14831  }
14832  else
14833  {
14835  {
14837  }
14838  Utilities->CallLogPop(232);
14839  return(false);
14840  }
14841  }
14842  // now start off in the best direction
14843  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
14844  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
14845  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
14846  // unless new problems are found.
14847  if(StartElement1.XLinkPos == BestPos)
14848  {
14849  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14850  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14851  AutoSigsFlag))
14852  {
14853  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
14854  if(PointsToBeChanged(8))
14855  {
14856  PointsChanged = true;
14857  }
14858  Utilities->CallLogPop(233);
14859  return(true);
14860  }
14861  else if(StartElement2.TrackVectorPosition > -1)
14862  {
14863  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14864  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14865  AutoSigsFlag))
14866  {
14867  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
14868  if(PointsToBeChanged(9))
14869  {
14870  PointsChanged = true;
14871  }
14872  Utilities->CallLogPop(234);
14873  return(true);
14874  }
14875  }
14876  }
14877  else if(StartElement2.TrackVectorPosition > -1)
14878  {
14879  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14880  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14881  AutoSigsFlag))
14882  {
14883  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
14884  if(PointsToBeChanged(10))
14885  {
14886  ;
14887  }
14888  {
14889  PointsChanged = true;
14890  }
14891  Utilities->CallLogPop(1857);
14892  return(true);
14893  }
14894  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14895  AutoSigsFlag))
14896  {
14897  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
14898  if(PointsToBeChanged(11))
14899  {
14900  ;
14901  }
14902  {
14903  PointsChanged = true;
14904  }
14905  Utilities->CallLogPop(1858);
14906  return(true);
14907  }
14908  }
14909  else if(StartElement1.XLinkPos == (1 - BestPos))
14910  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
14911  {
14912  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14913  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14914  AutoSigsFlag))
14915  {
14916  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
14917  if(PointsToBeChanged(12))
14918  {
14919  PointsChanged = true;
14920  }
14921  Utilities->CallLogPop(1864);
14922  return(true);
14923  }
14924  }
14925  }
14927  {
14929  }
14930  Utilities->CallLogPop(235);
14931  return(false);
14932 }
14933 
14934 // ---------------------------------------------------------------------------
14935 
14936 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
14937 {
14938  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
14939  if(PrefDirSize() == 0)
14940  {
14941  Utilities->CallLogPop(1704);
14942  return;
14943  }
14944  for(unsigned int x = 0; x < PrefDirSize(); x++)
14945  {
14946  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
14947  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
14948  {
14949  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14950  TempPrefDirElement.EXGraphicPtr);
14951  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
14952  {
14953  if(x == 0)
14954  {
14955  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14956  TempPrefDirElement.EntryDirectionGraphicPtr);
14957  }
14958  if(x == (PrefDirSize() - 1))
14959  {
14960  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14961  TempPrefDirElement.EntryDirectionGraphicPtr);
14962  }
14963  }
14964  }
14965  }
14966 
14967  Utilities->CallLogPop(1705);
14968 }
14969 
14970 // ---------------------------------------------------------------------------
14971 
14972 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
14973  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag)
14974 
14975 /*
14976  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
14977  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
14978  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
14979  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
14980  Return false if any element (apart from RequiredPosition) is on an existing route.
14981  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
14982 
14983  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
14984  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
14985  added during the function so as to leave it exactly as it was on entering, then return false).
14986  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
14987  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
14988  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
14989  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
14990  the route number that the searched-for element is the start of if any, and set to -1 if no
14991  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
14992  this unit, together with the ConsecSignalsRoute and AutoSigsFlag flags.
14993  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
14994  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
14995 
14996  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
14997  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
14998  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
14999  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
15000  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
15001  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
15002  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
15003  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
15004  or if train on element (unless a bridge & train on different track).
15005  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
15006  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
15007  a leading point where both trailing directions are in EveryPrefDir, if not fail.
15008  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
15009  AutoSignals member set if AutoSigsFlag set, then return true.
15010  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
15011 
15012  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
15013  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
15014  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
15015  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
15016  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
15017  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
15018  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
15019 
15020  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
15021  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
15022 */
15023 
15024 {
15025  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
15026  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
15027  AnsiString((short)AutoSigsFlag));
15028  int VectorCount = 0;
15029  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
15030 
15031 // check for a fouled diagonal for first element. Added for v1.3.2
15032  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
15033  {
15034  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
15035  {
15036  for(int x = 0; x < VectorCount; x++)
15037  {
15038  SearchVector.erase(SearchVector.end() - 1);
15039  }
15040  Utilities->CallLogPop(2043);
15041  return(false);
15042  }
15043  }
15044  bool FirstPass = true;
15045 
15046  while(true)
15047  {
15048  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
15049  {
15050  Track->LCFoundInAutoSigsRoute = true;
15051  }
15052  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
15053  {
15054  for(int x = 0; x < VectorCount; x++)
15055  {
15056  SearchVector.erase(SearchVector.end() - 1);
15057  }
15058  Utilities->CallLogPop(1926);
15059  return(false);
15060  }
15061  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
15062  {
15063  for(int x = 0; x < VectorCount; x++)
15064  {
15065  SearchVector.erase(SearchVector.end() - 1);
15066  }
15067  Utilities->CallLogPop(236);
15068  return(false);
15069  }
15070  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
15071  // reached a valid signal that isn't the required position, user should always select the next
15072  // signal in a route so have to fail
15073  // won't affect recurive searches as for them the first pass element is always a point
15074  {
15075  for(int x = 0; x < VectorCount; x++)
15076  {
15077  SearchVector.erase(SearchVector.end() - 1);
15078  }
15079  Utilities->CallLogPop(237);
15080  return(false);
15081  }
15082  FirstPass = false;
15083  int NextPosition = PrefDirElement.Conn[XLinkPos];
15084  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
15085  TPrefDirElement SearchElement(NextTrackElement);
15086  SearchElement.TrackVectorPosition = NextPosition;
15087  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
15088  SearchElement.ELinkPos = NextELinkPos;
15089  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
15090  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
15091  int NextXLinkPos;
15092  if(SearchElement.ELinkPos == 0)
15093  {
15094  NextXLinkPos = 1;
15095  }
15096  if(SearchElement.ELinkPos == 1)
15097  {
15098  NextXLinkPos = 0;
15099  }
15100  if(SearchElement.ELinkPos == 2)
15101  {
15102  NextXLinkPos = 3;
15103  }
15104  if(SearchElement.ELinkPos == 3)
15105  {
15106  NextXLinkPos = 2;
15107  }
15108  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
15109  {
15110  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
15111 // note that may be buffers, continuation or gap
15112  SearchElement.XLinkPos = NextXLinkPos;
15113  }
15114 // can't set XLink or XLinkPos yet if the element is a leading point.
15115 
15116 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
15117  for(unsigned int x = 0; x < SearchVector.size(); x++)
15118  {
15119  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
15120  {
15121  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
15122  // OK if a bridge & routes on different tracks
15123  {
15124  for(int x = 0; x < VectorCount; x++)
15125  {
15126  SearchVector.erase(SearchVector.end() - 1);
15127  }
15128  Utilities->CallLogPop(238);
15129  return(false);
15130  }
15131  }
15132  }
15133 
15134 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
15135  TAllRoutes::TRouteElementPair SecondPair;
15137  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
15138  if(RoutePair.first > -1)
15139  {
15140  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
15141  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
15142  RoutePair.second).ELinkPos)))
15143  {
15144  // still OK if start of an expected route
15145  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
15146  {
15147  for(int x = 0; x < VectorCount; x++)
15148  {
15149  SearchVector.erase(SearchVector.end() - 1);
15150  }
15151  Utilities->CallLogPop(239);
15152  return(false); // only allow for start of an expected route
15153  }
15154  }
15155  }
15156  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
15157  {
15158  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
15159  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
15160  SecondPair.second).ELinkPos)))
15161  {
15162  // still OK if start of an expected route
15163  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
15164  {
15165  for(int x = 0; x < VectorCount; x++)
15166  {
15167  SearchVector.erase(SearchVector.end() - 1);
15168  }
15169  Utilities->CallLogPop(240);
15170  return(false); // only allow for start of an expected route
15171  }
15172  }
15173  }
15174 // check if a train on element, unless a bridge & train on different track
15175 // OK of same train as start element - no drop this
15176 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
15177  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
15178  {
15179  for(int x = 0; x < VectorCount; x++)
15180  {
15181  SearchVector.erase(SearchVector.end() - 1);
15182  }
15183  Utilities->CallLogPop(241);
15184  return(false);
15185  }
15186  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
15187  {
15188  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
15189  {
15190  for(int x = 0; x < VectorCount; x++)
15191  {
15192  SearchVector.erase(SearchVector.end() - 1);
15193  }
15194  Utilities->CallLogPop(242);
15195  return(false);
15196  }
15197  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
15198  {
15199  for(int x = 0; x < VectorCount; x++)
15200  {
15201  SearchVector.erase(SearchVector.end() - 1);
15202  }
15203  Utilities->CallLogPop(243);
15204  return(false);
15205  }
15206  }
15207 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
15208  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15209  {
15210  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15211  {
15212  for(int x = 0; x < VectorCount; x++)
15213  {
15214  SearchVector.erase(SearchVector.end() - 1);
15215  }
15216  Utilities->CallLogPop(244);
15217  return(false);
15218  }
15219  }
15220 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
15221 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
15222  bool InPrefDirFlag = false;
15223  PrefDirElement1 = BlankElement;
15224  PrefDirElement2 = BlankElement;
15225 
15226  bool FoundFlag;
15227  int PrefDirPos0 = -1;
15228  int PrefDirPos1 = -1;
15229  int PrefDirPos2 = -1;
15230  int PrefDirPos3 = -1;
15232  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15233  int PrefDirVecPos[4] =
15234  {
15235  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15236  };
15237  for(int x = 0; x < 4; x++)
15238  {
15239  int b = PrefDirVecPos[x];
15240  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
15241  {
15242  InPrefDirFlag = true;
15243  if(PrefDirElement1.TrackVectorPosition == -1)
15244  {
15245  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
15246  }
15247  else
15248  {
15249  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
15250  }
15251  }
15252  }
15253  if(!InPrefDirFlag)
15254  {
15255  for(int x = 0; x < VectorCount; x++)
15256  {
15257  SearchVector.erase(SearchVector.end() - 1);
15258  }
15259  Utilities->CallLogPop(245);
15260  return(false);
15261  }
15262 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
15263 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
15264 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
15266  {
15267  for(int x = 0; x < VectorCount; x++)
15268  {
15269  SearchVector.erase(SearchVector.end() - 1);
15270  }
15271  Utilities->CallLogPop(1690);
15272  return(false);
15273  }
15274 // check if found it
15275  if(SearchElement.TrackVectorPosition == RequiredPosition)
15276  {
15277 // need to ensure a signal/buffer/continuation
15278  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End) &&
15279  (SearchElement.Config[SearchElement.XLinkPos] != Continuation))
15280  {
15281  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
15283  for(int x = 0; x < VectorCount; x++)
15284  {
15285  SearchVector.erase(SearchVector.end() - 1);
15286  }
15287  Utilities->CallLogPop(246);
15288  return(false);
15289  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal).......
15290 
15291  if(AutoSigsFlag)
15292  {
15293  PrefDirElement1.AutoSignals = true;
15294  }
15295  PrefDirElement1.PrefDirRoute = true;
15297  {
15299  {
15300  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
15302  }
15303  for(int x = 0; x < VectorCount; x++)
15304  {
15305  SearchVector.erase(SearchVector.end() - 1);
15306  }
15307  Utilities->CallLogPop(1928);
15308  return(false);
15309  }
15310  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
15311  VectorCount++; // not really needed but include for tidyness
15312  TotalSearchCount++;
15313  Utilities->CallLogPop(247);
15314  return(true);
15315  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
15316 
15317 // check if a buffer or continuation (end of search on this leg if not found by now)
15318  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
15319  {
15320  for(int x = 0; x < VectorCount; x++)
15321  {
15322  SearchVector.erase(SearchVector.end() - 1);
15323  }
15324  Utilities->CallLogPop(248);
15325  return(false);
15326  }
15327 // check if SearchVector exceeds a size of 150
15328  if(SearchVector.size() > 150)
15329  {
15330  for(int x = 0; x < VectorCount; x++)
15331  {
15332  SearchVector.erase(SearchVector.end() - 1);
15333  }
15334  Utilities->CallLogPop(1420);
15335  return(false);
15336  }
15337 // check if reached a leading point
15338  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
15339  {
15340 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
15341  int SearchPos1 = SearchElement.Attribute + 1;
15342  int SearchPos2;
15343  if(SearchPos1 == 2)
15344  {
15345  SearchPos1++;
15346  }
15347  if(SearchPos1 == 1)
15348  {
15349  SearchPos2 = 3;
15350  }
15351  else
15352  {
15353  SearchPos2 = 1;
15354  }
15355  SearchElement.XLink = SearchElement.Link[SearchPos1];
15356  SearchElement.XLinkPos = SearchPos1;
15357  InPrefDirFlag = false;
15358  if(SearchElement.XLink == PrefDirElement1.XLink)
15359  {
15360  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15361  InPrefDirFlag = true;
15362  }
15363  else if(SearchElement.XLink == PrefDirElement2.XLink)
15364  {
15365  SearchElement = PrefDirElement2;
15366  InPrefDirFlag = true;
15367  }
15368 // push element with XLink set to position [SearchPos1] if on a PrefDir
15369  if(InPrefDirFlag)
15370  {
15371 // check for a fouled diagonal for leading point for XLinkPos == 1)
15372  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15373  {
15374  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15375  {
15376  for(int x = 0; x < VectorCount; x++)
15377  {
15378  SearchVector.erase(SearchVector.end() - 1);
15379  }
15380  Utilities->CallLogPop(249);
15381  return(false);
15382  }
15383  }
15384  if(AutoSigsFlag)
15385  {
15386  SearchElement.AutoSignals = true;
15387  }
15388  SearchElement.PrefDirRoute = true;
15389  SearchVector.push_back(SearchElement);
15390  VectorCount++;
15391  TotalSearchCount++;
15392 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
15393  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15394  AutoSigsFlag))
15395  {
15397  {
15399  {
15400  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
15402  }
15403  for(int x = 0; x < VectorCount; x++)
15404  {
15405  SearchVector.erase(SearchVector.end() - 1);
15406  }
15407  Utilities->CallLogPop(1929);
15408  return(false);
15409  }
15410  Utilities->CallLogPop(250);
15411  return(true);
15412  }
15413  else
15414  {
15415 // remove leading point with XLinkPos [1]
15416  SearchVector.erase(SearchVector.end() - 1);
15417  VectorCount--;
15418  }
15419  }
15420 // XLink set to position [SearchPos2]
15421  SearchElement.XLink = SearchElement.Link[SearchPos2];
15422  SearchElement.XLinkPos = SearchPos2;
15423  if(SearchElement.XLink == PrefDirElement1.XLink)
15424  {
15425  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15426  }
15427  else if(SearchElement.XLink == PrefDirElement2.XLink)
15428  {
15429  SearchElement = PrefDirElement2;
15430  }
15431  else // failed to find a valid exit from the point
15432  {
15433  for(int x = 0; x < VectorCount; x++)
15434  {
15435  SearchVector.erase(SearchVector.end() - 1);
15436  }
15437  Utilities->CallLogPop(251);
15438  return(false);
15439  }
15440 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
15441  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15442  {
15443  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15444  {
15445  for(int x = 0; x < VectorCount; x++)
15446  {
15447  SearchVector.erase(SearchVector.end() - 1);
15448  }
15449  Utilities->CallLogPop(252);
15450  return(false);
15451  }
15452  }
15453 // push element with XLink set to position [SearchPos2]
15454  if(AutoSigsFlag)
15455  {
15456  SearchElement.AutoSignals = true;
15457  }
15458  SearchElement.PrefDirRoute = true;
15459  SearchVector.push_back(SearchElement);
15460  VectorCount++;
15461  TotalSearchCount++;
15462 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
15463  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15464  AutoSigsFlag))
15465  {
15467  {
15469  {
15470  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
15472  }
15473  for(int x = 0; x < VectorCount; x++)
15474  {
15475  SearchVector.erase(SearchVector.end() - 1);
15476  }
15477  Utilities->CallLogPop(1930);
15478  return(false);
15479  }
15480  Utilities->CallLogPop(1592);
15481  return(true);
15482  }
15483  else
15484  {
15485  for(int x = 0; x < VectorCount; x++)
15486  {
15487  SearchVector.erase(SearchVector.end() - 1);
15488  }
15489  Utilities->CallLogPop(253);
15490  return(false);
15491  }
15492  } // if leading point
15493 
15494 // here if ordinary element, push it, inc vector & update PrefDirElement ready for next element on PrefDir
15495  SearchElement = PrefDirElement1;
15496  if(AutoSigsFlag)
15497  {
15498  SearchElement.AutoSignals = true;
15499  }
15500  SearchElement.PrefDirRoute = true;
15501  SearchVector.push_back(SearchElement);
15502  VectorCount++;
15503  TotalSearchCount++;
15504  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
15505  PrefDirElement = SearchElement;
15506  } // while(true)
15507 }
15508 
15509 // ---------------------------------------------------------------------------
15510 
15511 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
15512 {
15513 /*
15514  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
15515  and the new or extended route created from that. Hence action varies depending on whether
15516  it is a completely new route, or an extension of an existing route at the beginning or the end.
15517  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
15518  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
15519 
15520  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
15521  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
15522  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
15523  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
15524  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
15525  is decremented;
15526  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
15527  from the existing route, then enter the new route into the AllRoutesVector;
15528  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15529  then enter the new route into the AllRoutesVector.
15530 
15531  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
15532  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
15533  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
15534  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
15535  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15536  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
15537  for the new route and return;
15538  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
15539  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
15540 
15541  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
15542  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
15543  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
15544 
15545 */
15546  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
15547  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
15548  if(SearchVector.size() < 1)
15549  {
15550  Utilities->CallLogPop(254);
15551  return;
15552  }
15554  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
15555  {
15556  Utilities->CallLogPop(255);
15557  return;
15558  }
15559  TAllRoutes::TLockedRouteClass LockedRouteObject;
15560 
15562  unsigned int TruncatePrefDirPosition = 0;
15563 
15564  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
15565 /* if have ReqPosRouteID:
15566  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
15567  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
15568  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
15569  the existing route, then enter the new route into the AllRoutesVector
15570  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15571  then enter the new route into the AllRoutesVector
15572 */
15573  {
15576  {
15577  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
15578  x++) // start at 1 as first element already in SearchVector
15579  {
15581  }
15582  // note that route numbers in map adjusted when ReqPos route cleared
15584  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
15585  // set during ClearRouteDuringRouteBuildingAt
15587  {
15590  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
15591  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
15592  }
15593  }
15595  {
15597  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15598  }
15600  {
15601  SearchVector.pop_back();
15602  }
15603  }
15604  if(StartSelectionRouteID > -1)
15605 /* if have StartSelectionRouteID:
15606  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
15607  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
15608  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15609  then add it to the start of the new route, then enter the new route into the AllRoutesVector
15610  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15611 */
15612  {
15614  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
15615  {
15618  {
15619  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
15620  for(unsigned int x = 0; x < SearchVector.size(); x++)
15621  {
15623  RouteNumber, GetFixedSearchElementAt(3, x));
15624  // find & store locked route truncate position in PrefDirVector for later use
15626  {
15627  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
15628  {
15629  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
15630  }
15631  }
15632  }
15634  {
15635  throw Exception("Error - failed to validate extended route for preferred route");
15636  }
15639  if(!AutoSigsFlag)
15640  {
15641  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
15642  }
15643  // now add the reinstated locked route if required and set signals accordingly
15645  {
15646  LockedRouteObject.RouteNumber = RouteNumber;
15647  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
15648  // now reset the signals for the locked route
15649  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
15650  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
15651  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
15652  {
15653  // return all signals to red in route section to be truncated
15654  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
15655  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
15656  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15657  {
15658  TrackElement.Attribute = 0;
15659  Track->PlotSignal(10, TrackElement, Display);
15660  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15661  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15662  }
15663  }
15664  }
15665  AllRoutes->CheckMapAndRoutes(1); // test
15666  Utilities->CallLogPop(256);
15667  return;
15668  }
15670  {
15673  RouteElement.AutoSignals = true;
15674  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
15675  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
15676  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15677  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
15678  }
15679  }
15680  else
15681  {
15683  }
15684 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
15685 // AllRoutesVector hence nothing to do here
15686  }
15687  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
15688  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
15689  {
15690  throw Exception("Error - failed to validate single route for preferred route");
15691  }
15692  AllRoutes->StoreOneRoute(1, this);
15693  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
15694  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
15695  if(!AutoSigsFlag)
15696  {
15697  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
15698  }
15699  AllRoutes->CheckMapAndRoutes(2); // test
15700  Utilities->CallLogPop(257);
15701 }
15702 
15703 // ---------------------------------------------------------------------------
15704 
15705 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
15706 {
15707 /*
15708  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
15709  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
15710  & ensure signal/buffers/continuation.
15711  Note that can't select ConsecSignalsRoute for non-preferred routes.
15712  Check if train on element & disallow.
15713  Set default values for retained parameters:-
15714  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
15715  StartSelectionRouteID = route that selection starts in if there is one;
15716 
15717  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
15718  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
15719  validity. This is just for safety reasons, the PrefDir values aren't used.
15720  StartElement1 & 2 are set to these PrefDirelements.
15721 
15722  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
15723 
15724  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
15725  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
15726  blank StartElement2 (only want to use the route element), then return true.
15727  Check if adjacent to start or end of an existing route & disallow if so.
15728  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
15729  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
15730  SetRemainingSearchVectorValues().
15731  Finally add the required element to the SearchVector & return true.
15732 
15733 */
15734  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
15735  AnsiString(VLoc) + "," + AnsiString((short)Callon));
15736  ClearRoute();
15737  int TrackVectorPosition;
15738  TTrackElement TrackElement;
15739  TPrefDirElement FirstElement, LastElement;
15740 
15741  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
15742  {
15743  Utilities->CallLogPop(258);
15744  return(false);
15745  }
15746  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
15747  {
15748  if(!Callon)
15749  {
15750  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
15751  }
15752 // makes later adjacent route checks too complicated
15753  Utilities->CallLogPop(259);
15754  return(false);
15755  }
15756  if(Track->IsLCAtHV(21, HLoc, VLoc))
15757  {
15758  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
15759  Utilities->CallLogPop(1910);
15760  return(false);
15761  }
15762 // check if selected a train & disallow if so
15763  if(TrackElement.TrainIDOnElement > -1)
15764  {
15765  if(!Callon)
15766  {
15767  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
15768  }
15769  Utilities->CallLogPop(260);
15770  return(false);
15771  }
15772 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
15773  TPrefDirElement PrefDirElement;
15774  int LockedVectorNumber;
15775 
15776  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
15777  {
15778  if(!Callon)
15779  {
15780  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
15781  }
15782  Utilities->CallLogPop(261);
15783  return(false);
15784  }
15785  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
15786  {
15787  if(!Callon)
15788  {
15789  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
15790  }
15791  Utilities->CallLogPop(262);
15792  return(false);
15793  }
15795 // AdjacentStartRouteNumber = -1;
15796  StartRoutePosition = TrackVectorPosition;
15797 // StartRouteSelectPosition = TrackVectorPosition;
15798 
15799  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
15800  TPrefDirElement PrefDirElement2(TrackElement);
15801 
15802  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
15803  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
15804  TPrefDirElement BlankElement;
15805 
15806  PrefDirElement1.ELinkPos = 0;
15807  PrefDirElement1.XLinkPos = 1;
15808  PrefDirElement1.ELink = PrefDirElement1.Link[0];
15809  PrefDirElement1.XLink = PrefDirElement1.Link[1];
15810  if(!(PrefDirElement1.EntryExitNumber()))
15811  {
15812  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
15813  // no need for bridge check as bridge selections not allowed
15814  }
15815  PrefDirElement1.CheckCount = 9;
15816  PrefDirElement2.ELinkPos = 1;
15817  PrefDirElement2.XLinkPos = 0;
15818  PrefDirElement2.ELink = PrefDirElement2.Link[1];
15819  PrefDirElement2.XLink = PrefDirElement2.Link[0];
15820  if(!(PrefDirElement2.EntryExitNumber()))
15821  {
15822  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
15823  }
15824  PrefDirElement2.CheckCount = 9; // both now set
15825 
15826 // set StartElements to the above PrefDirElements
15827  StartElement1 = PrefDirElement1;
15828  StartElement2 = PrefDirElement2;
15829 
15830 // no PrefDir check needed as doesn't need to be in a PrefDir
15831 
15832 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
15834  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15835 
15836  if(RoutePair.first > -1)
15837  {
15838  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
15839  {
15840  if(!Callon)
15841  {
15842  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
15843  }
15844  Utilities->CallLogPop(263);
15845  return(false);
15846  }
15847  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
15848  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
15849  {
15850  if(!Callon)
15851  {
15852  TrainController->StopTTClockMessage(39, "No forward connection from this position");
15853  }
15854  Utilities->CallLogPop(264);
15855  return(false);
15856  }
15857  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
15858  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
15859  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15860  {
15861  if(!Callon)
15862  {
15863  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
15864  }
15865  Utilities->CallLogPop(265);
15866  return(false);
15867  }
15868  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
15870  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
15871  StartElement2 = BlankElement; // only use the route element
15873  Utilities->CallLogPop(266);
15874  return(true); // all retained values set
15875  }
15876 
15877  else // selection not in an existing route
15878  {
15879 // check if it's adjacent to start of an an existing route,
15880  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15881  {
15882  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
15883  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
15884  {
15885  if(!Callon)
15886  {
15887  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
15888  }
15889  Utilities->CallLogPop(267);
15890  return(false);
15891  }
15892  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
15893  {
15894  if(!Callon)
15895  {
15896  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
15897  }
15898  Utilities->CallLogPop(268);
15899  return(false);
15900  }
15901  }
15902 // check if it's adjacent to end of an an existing route,
15903  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15904  {
15906  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
15907  {
15908  if(!Callon)
15909  {
15910  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
15911  }
15912  Utilities->CallLogPop(269);
15913  return(false);
15914  }
15915  }
15916  // not in a route or adjacent to start or end of a route
15917  // in this case reset all variable values to -1 & CheckCount to 4
15918  StartElement1.ELink = -1;
15919  StartElement1.ELinkPos = -1;
15920  StartElement1.XLink = -1;
15921  StartElement1.XLinkPos = -1;
15922  StartElement1.EXNumber = -1;
15924  StartElement2 = BlankElement;
15925  SearchVector.push_back(StartElement1);
15926  Utilities->CallLogPop(270);
15927  return(true);
15928  }
15929 }
15930 
15931 // ---------------------------------------------------------------------------
15932 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
15933 
15934 /*
15935  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
15936 
15937  Declare the following integers:-
15938  EndPosition - TrackVectorPosition for the selection;
15939  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
15940  Check if selection is a valid track element and set EndPosition.
15941  Cancel if select original start element, then check that not points, bridge or crossover.
15942  Check & fail if a train is present at the selection.
15943  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
15944  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
15945  No check needed for selection in EveryPrefDir.
15946  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
15947  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
15948  as don't need it if in a route.
15949  Check if selection adj to start or end of a route and disallow.
15950  Fail if select same route as starting route, though should already have failed earlier if this is so.
15951 
15952  If there's a StartSelectionRouteID then StartElement1 will be set to
15953  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
15954  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
15955  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
15956  to add the new route to the AllRoutesVectorPtr.
15957  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
15958  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
15959  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
15960  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
15961  the search vector values and return.
15962  If not returned yet then have failed to find the required element so return false with no message.
15963 
15964 */
15965 
15966 {
15967 // get EndPosition
15968  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
15969  AnsiString(VLoc));
15970  int EndPosition;
15971 
15972  TotalSearchCount = 0;
15973  ReqPosRouteID = IDInt(-1); // for not used
15974  TTrackElement TrackElement;
15975  TPrefDirElement BlankElement;
15976 
15977  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
15978  {
15979  Utilities->CallLogPop(271);
15980  return(false);
15981  }
15982 // EndPosition = EndSelectPosition;
15983 // cancel selection if on original start element
15984  if(EndPosition == StartRoutePosition)
15985  {
15986  Utilities->CallLogPop(272);
15987  return(false);
15988  }
15989  if(Track->IsLCAtHV(22, HLoc, VLoc))
15990  {
15991  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
15992  Utilities->CallLogPop(1911);
15993  return(false);
15994  }
15995  if((TrackElement.TrackType == Points) && !Callon)
15996  {
15997  if(!Callon)
15998  {
15999  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
16000  }
16001 // makes later adjacent route checks too complicated
16002  Utilities->CallLogPop(273);
16003  return(false);
16004  }
16005  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
16006  {
16007  if(!Callon)
16008  {
16009  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
16010  }
16011 // makes later adjacent route checks too complicated
16012  Utilities->CallLogPop(1861);
16013  return(false);
16014  }
16015 // check if train on element
16016  if(TrackElement.TrainIDOnElement > -1)
16017  {
16018  if(!Callon)
16019  {
16020  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
16021  }
16022  Utilities->CallLogPop(274);
16023  return(false);
16024  }
16025 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
16026 // check passed)
16027  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
16028  TPrefDirElement EndElement2(TrackElement);
16029 
16030  EndElement1.TrackVectorPosition = EndPosition;
16031  EndElement2.TrackVectorPosition = EndPosition;
16032  EndElement1.ELinkPos = 0;
16033  EndElement1.XLinkPos = 1;
16034  EndElement1.ELink = EndElement1.Link[0];
16035  EndElement1.XLink = EndElement1.Link[1];
16036  if(!(EndElement1.EntryExitNumber()))
16037  {
16038  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
16039  }
16040  EndElement1.CheckCount = 9;
16041  EndElement2.ELinkPos = 1;
16042  EndElement2.XLinkPos = 0;
16043  EndElement2.ELink = EndElement2.Link[1];
16044  EndElement2.XLink = EndElement2.Link[0];
16045  if(!(EndElement2.EntryExitNumber()))
16046  {
16047  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
16048  }
16049  EndElement2.CheckCount = 9; // both now set
16050 
16051 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
16052 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
16053 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
16054 
16055  if(EndElement1.HLoc >= StartElement1.HLoc)
16056  {
16058  SearchLimitHighH = EndElement1.HLoc + 15;
16059  }
16060  else
16061  {
16062  SearchLimitLowH = EndElement1.HLoc - 15;
16064  }
16065  if(EndElement1.VLoc >= StartElement1.VLoc)
16066  {
16068  SearchLimitHighV = EndElement1.VLoc + 15;
16069  }
16070  else
16071  {
16072  SearchLimitLowV = EndElement1.VLoc - 15;
16074  }
16075 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
16076  check & TotalSearchCounts check
16077  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
16078  {
16079  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
16080  Utilities->CallLogPop(1694);
16081  return false;
16082  }
16083 */
16084 // don't need EveryPrefDir check for NonPreferredRoute
16085 
16086 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
16087 // bool InRoute = false;
16089  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
16090 
16091  if(RoutePair.first > -1)
16092  {
16093  if(RoutePair.second != 0) // not first element in existing route so no good
16094  {
16095  if(!Callon)
16096  {
16097  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
16098  }
16099  Utilities->CallLogPop(275);
16100  return(false);
16101  }
16102  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
16103 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
16104  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
16105  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
16106  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
16107  {
16108  if(!Callon)
16109  {
16110  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
16111  }
16112  Utilities->CallLogPop(276);
16113  return(false);
16114  }
16115  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
16116  EndElement2 = BlankElement; // only need the route element
16117  EndPosition = EndElement1.TrackVectorPosition;
16118  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
16119  }
16120 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
16121  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16122  {
16123  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
16124  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
16125 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
16126 // && (AdjPosition != StartRoutePosition))
16127  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
16128  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
16129  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
16130  {
16131  if(!Callon)
16132  {
16133  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
16134  }
16135  Utilities->CallLogPop(277);
16136  return(false);
16137  }
16138 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
16139 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
16140  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
16141  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
16142  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
16143  (AdjPosition != StartRoutePosition))
16144  {
16145  if(!Callon)
16146  {
16147  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
16148  }
16149  Utilities->CallLogPop(278);
16150  return(false);
16151  }
16152 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
16154  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
16155  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
16156  {
16157  if(!Callon)
16158  {
16159  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
16160  }
16161  Utilities->CallLogPop(279);
16162  return(false);
16163  }
16164  }
16165 
16166 // check for same route as start element
16168  {
16169  if(!Callon)
16170  {
16171  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
16172  }
16173  Utilities->CallLogPop(280);
16174  return(false);
16175  }
16176 // check for a looping route
16177  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
16178  {
16180  {
16181  if(!Callon)
16182  {
16183  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
16184  }
16185  Utilities->CallLogPop(1845);
16186  return(false);
16187  }
16188  }
16189 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
16190 // so search from this element.
16191 
16192  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
16193 
16194  if(StartSelectionRouteID > -1)
16195  {
16196  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID))
16197  {
16199  if(PointsToBeChanged(0))
16200  {
16201  PointsChanged = true;
16202  }
16203  Utilities->CallLogPop(281);
16204  return(true);
16205  }
16206  else
16207  {
16208  if(!Callon)
16209  {
16211  }
16212  Utilities->CallLogPop(282);
16213  return(false);
16214  }
16215  }
16216  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
16217  // search on the 2 ways out of the element, which has to be a 2-ended element
16218  {
16219 // check if selection adjacent to start element and if so use that
16220  if(SearchVector.at(0).Conn[0] == EndPosition)
16221  {
16222  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID))
16223  {
16225  if(PointsToBeChanged(1))
16226  {
16227  PointsChanged = true;
16228  }
16229  Utilities->CallLogPop(283);
16230  return(true);
16231  }
16232  else
16233  {
16234  if(!Callon)
16235  {
16237  }
16238  Utilities->CallLogPop(284);
16239  return(false);
16240  }
16241  }
16242  else if(SearchVector.at(0).Conn[1] == EndPosition)
16243  {
16244  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID))
16245  {
16247  if(PointsToBeChanged(2))
16248  {
16249  PointsChanged = true;
16250  }
16251  Utilities->CallLogPop(285);
16252  return(true);
16253  }
16254  else
16255  {
16256  if(!Callon)
16257  {
16259  }
16260  Utilities->CallLogPop(286);
16261  return(false);
16262  }
16263  }
16264  // now start off in the best direction
16265  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
16266 
16267  if(SearchVector.at(0).Config[BestPos] != End)
16268  {
16269  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16270  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID))
16271  {
16273  if(PointsToBeChanged(3))
16274  {
16275  PointsChanged = true;
16276  }
16277  Utilities->CallLogPop(287);
16278  return(true);
16279  }
16280  }
16281  if(SearchVector.at(0).Config[1 - BestPos] != End)
16282  {
16283  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16284  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID))
16285  {
16287  if(PointsToBeChanged(4))
16288  {
16289  PointsChanged = true;
16290  }
16291  Utilities->CallLogPop(288);
16292  return(true);
16293  }
16294  }
16295  }
16296  if(!Callon)
16297  {
16299  }
16300  Utilities->CallLogPop(289);
16301  return(false);
16302 }
16303 
16304 // ---------------------------------------------------------------------------
16305 
16306 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
16307 /*
16308  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
16309  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
16310  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
16311  Keep a count of entries in SearchVector during the current function call, so that this number can be
16312  erased for an unproductive branch search.
16313  First check (within the loop) whether XLink leads to an End & return false if so.
16314  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
16315  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
16316  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
16317  train on element (unless a bridge & train on different track), or if element
16318  fouls an existing diagonal route (except if element is a leading point - these checked later).
16319  Then check if found required element. If so save it & return true.
16320  If not the required element check if buffer or continuation, & if so erase all searchvector
16321  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
16322  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
16323  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
16324  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
16325  When return true have 8 items from CheckCount established, only waiting for EXNumber
16326 */
16327 {
16328  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
16329  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
16330  int VectorCount = 0;
16331 
16332 // check for a fouled diagonal for first element. Added for v1.3.2
16333  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
16334  (CurrentTrackElement.Link[XLinkPos] == 9))
16335  {
16336  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
16337  {
16338  for(int x = 0; x < VectorCount; x++)
16339  {
16340  SearchVector.erase(SearchVector.end() - 1);
16341  }
16342  Utilities->CallLogPop(2044);
16343  return(false);
16344  }
16345  }
16346  while(true)
16347  {
16348  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
16349  {
16350  for(int x = 0; x < VectorCount; x++)
16351  {
16352  SearchVector.erase(SearchVector.end() - 1);
16353  }
16354  Utilities->CallLogPop(1927);
16355  return(false);
16356  }
16357  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
16358  {
16359  for(int x = 0; x < VectorCount; x++)
16360  {
16361  SearchVector.erase(SearchVector.end() - 1);
16362  }
16363  Utilities->CallLogPop(290);
16364  return(false);
16365  }
16366  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
16367  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
16368  TPrefDirElement SearchElement(NextTrackElement);
16369  SearchElement.TrackVectorPosition = NextPosition;
16370  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
16371  SearchElement.ELinkPos = NextELinkPos;
16372  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
16373  int NextXLinkPos;
16374  if(SearchElement.ELinkPos == 0)
16375  {
16376  NextXLinkPos = 1;
16377  }
16378  if(SearchElement.ELinkPos == 1)
16379  {
16380  NextXLinkPos = 0;
16381  }
16382  if(SearchElement.ELinkPos == 2)
16383  {
16384  NextXLinkPos = 3;
16385  }
16386  if(SearchElement.ELinkPos == 3)
16387  {
16388  NextXLinkPos = 2;
16389  }
16390  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
16391  {
16392  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
16393  // but may be buffers, continuation or gap
16394  SearchElement.XLinkPos = NextXLinkPos;
16395  }
16396 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
16397 // can't set XLink or XLinkPos yet if the element is a leading point.
16398 
16399 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
16400  for(unsigned int x = 0; x < SearchVector.size(); x++)
16401  {
16402  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
16403  {
16404  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
16405  // OK if it's a bridge & routes on different tracks
16406  {
16407  for(int x = 0; x < VectorCount; x++)
16408  {
16409  SearchVector.erase(SearchVector.end() - 1);
16410  }
16411  Utilities->CallLogPop(291);
16412  return(false);
16413  }
16414  }
16415  }
16416 
16417 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16418  TAllRoutes::TRouteElementPair SecondPair;
16420  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16421  if(RoutePair.first > -1)
16422  {
16423  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16424  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
16425  RoutePair.second).ELinkPos)))
16426  {
16427  // still OK if start of an expected route
16428  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
16429  {
16430  for(int x = 0; x < VectorCount; x++)
16431  {
16432  SearchVector.erase(SearchVector.end() - 1);
16433  }
16434  Utilities->CallLogPop(292);
16435  return(false); // only allow for start of an expected route
16436  }
16437  }
16438  }
16439  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16440  {
16441  // OK if it's a bridge & routes on different tracks
16442  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
16443  SecondPair.second).ELinkPos)))
16444  {
16445  // still OK if start of an expected route
16446  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
16447  {
16448  for(int x = 0; x < VectorCount; x++)
16449  {
16450  SearchVector.erase(SearchVector.end() - 1);
16451  }
16452  Utilities->CallLogPop(293);
16453  return(false); // only allow for start of an expected route
16454  }
16455  }
16456  }
16457 // check if a train on element, unless a bridge & train on different track
16458 // OK of same train as start element - no, drop this
16459 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16460  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16461  {
16462  for(int x = 0; x < VectorCount; x++)
16463  {
16464  SearchVector.erase(SearchVector.end() - 1);
16465  }
16466  Utilities->CallLogPop(294);
16467  return(false);
16468  }
16469  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16470  {
16471  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
16472  {
16473  for(int x = 0; x < VectorCount; x++)
16474  {
16475  SearchVector.erase(SearchVector.end() - 1);
16476  }
16477  Utilities->CallLogPop(295);
16478  return(false);
16479  }
16480  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
16481  {
16482  for(int x = 0; x < VectorCount; x++)
16483  {
16484  SearchVector.erase(SearchVector.end() - 1);
16485  }
16486  Utilities->CallLogPop(296);
16487  return(false);
16488  }
16489  }
16490 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
16491  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16492  {
16493  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16494  {
16495  for(int x = 0; x < VectorCount; x++)
16496  {
16497  SearchVector.erase(SearchVector.end() - 1);
16498  }
16499  Utilities->CallLogPop(297);
16500  return(false);
16501  }
16502  }
16503 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16504 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16505 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16507  {
16508  for(int x = 0; x < VectorCount; x++)
16509  {
16510  SearchVector.erase(SearchVector.end() - 1);
16511  }
16512  Utilities->CallLogPop(1689);
16513  return(false);
16514  }
16515 // check if found it
16516  if(SearchElement.TrackVectorPosition == RequiredPosition)
16517  {
16518  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
16519  {
16520  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
16521  {
16522  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
16523  }
16524  else
16525  {
16526  SearchElement.XLinkPos = 1;
16527  }
16528 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
16529  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
16530  }
16531  SearchVector.push_back(SearchElement);
16532  VectorCount++; // not really needed but include for tidyness
16533  TotalSearchCount++;
16534  Utilities->CallLogPop(298);
16535  return(true);
16536  }
16537 // Not the required element - check if a buffer or continuation
16538  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16539  {
16540  for(int x = 0; x < VectorCount; x++)
16541  {
16542  SearchVector.erase(SearchVector.end() - 1);
16543  }
16544  Utilities->CallLogPop(299);
16545  return(false);
16546  }
16547 // check if SearchVector exceeds a size of 150
16548  if(SearchVector.size() > 150)
16549  {
16550  for(int x = 0; x < VectorCount; x++)
16551  {
16552  SearchVector.erase(SearchVector.end() - 1);
16553  }
16554  Utilities->CallLogPop(1421);
16555  return(false);
16556  }
16557 // check if reached a leading point
16558  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
16559  {
16560 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
16561  int SearchPos1 = SearchElement.Attribute + 1;
16562  int SearchPos2;
16563  if(SearchPos1 == 2)
16564  {
16565  SearchPos1++;
16566  }
16567  if(SearchPos1 == 1)
16568  {
16569  SearchPos2 = 3;
16570  }
16571  else
16572  {
16573  SearchPos2 = 1;
16574  }
16575 // push element with XLink set to position [SearchPos1]
16576  SearchElement.XLink = SearchElement.Link[SearchPos1];
16577  SearchElement.XLinkPos = SearchPos1;
16578 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
16579  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16580  {
16581  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16582  {
16583  for(int x = 0; x < VectorCount; x++)
16584  {
16585  SearchVector.erase(SearchVector.end() - 1);
16586  }
16587  Utilities->CallLogPop(300);
16588  return(false);
16589  }
16590  }
16591  SearchVector.push_back(SearchElement);
16592  VectorCount++;
16593  TotalSearchCount++;
16594 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
16595 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
16596 // recursive search as has to be a TTrackElement for non-preferred route searches
16597  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID))
16598  {
16599  Utilities->CallLogPop(301);
16600  return(true);
16601  }
16602  else
16603  {
16604 // remove leading point with XLinkPos [SearchPos1]
16605  SearchVector.erase(SearchVector.end() - 1);
16606  VectorCount--;
16607 // push element with XLink set to position [SearchPos2]
16608  SearchElement.XLink = SearchElement.Link[SearchPos2];
16609  SearchElement.XLinkPos = SearchPos2;
16610 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
16611  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16612  {
16613  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16614  {
16615  for(int x = 0; x < VectorCount; x++)
16616  {
16617  SearchVector.erase(SearchVector.end() - 1);
16618  }
16619  Utilities->CallLogPop(302);
16620  return(false);
16621  }
16622  }
16623  SearchVector.push_back(SearchElement);
16624  VectorCount++;
16625  TotalSearchCount++;
16626 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
16627  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID))
16628  {
16629  Utilities->CallLogPop(303);
16630  return(true);
16631  }
16632  else
16633  {
16634  for(int x = 0; x < VectorCount; x++)
16635  {
16636  SearchVector.erase(SearchVector.end() - 1);
16637  }
16638  Utilities->CallLogPop(304);
16639  return(false);
16640  }
16641  }
16642  } // if leading point
16643 
16644 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
16645 // ready for next element on route
16646  SearchVector.push_back(SearchElement);
16647  VectorCount++;
16648  TotalSearchCount++;
16649  CurrentTrackElement = SearchElement;
16650  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
16651  } // while(true)
16652 }
16653 
16654 // ---------------------------------------------------------------------------
16655 
16657 
16658 /*
16659  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
16660  having all values set (since not necessarily on PrefDirs).
16661  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
16662  (if it was the start), so these are checked first and set if necessary. All elements now have
16663  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
16664  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
16665  to set the route colour and direction graphics.
16666 */
16667 
16668 {
16669  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
16670  if(SearchVector.size() == 0)
16671  {
16672  throw Exception("Error, SearchVector empty");
16673  }
16674 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
16675 // hence need to examine and update it if necessary
16676  TPrefDirElement SecondElement;
16677 
16678  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
16679  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
16680  // need above check or SecondElement will fail
16681  {
16682  SecondElement = SearchVector.at(1);
16683  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
16684  for(int x = 0; x < 4; x++)
16685  {
16686  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
16687  {
16688  if(SearchVector.at(0).XLink == -1) // i.e. not set
16689  {
16690  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
16691  SearchVector.at(0).XLinkPos = x;
16692  }
16693  int ELinkPos;
16694  if(SearchVector.at(0).XLinkPos == 0)
16695  {
16696  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
16697  }
16698  // linked to 1st searchvector element, & if XLink was set then x may not correspond
16699  if(SearchVector.at(0).XLinkPos == 1)
16700  {
16701  ELinkPos = 0;
16702  }
16703  if(SearchVector.at(0).XLinkPos == 2)
16704  {
16705  ELinkPos = 3;
16706  }
16707  if(SearchVector.at(0).XLinkPos == 3)
16708  {
16709  ELinkPos = 2;
16710  }
16711  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
16712  {
16713  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
16714  SearchVector.at(0).ELinkPos = ELinkPos;
16715  }
16716  break; // no point going any further
16717  }
16718  }
16719  }
16720  for(unsigned int x = 0; x < SearchVector.size(); x++)
16721  {
16722  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
16723 // set EXNumber
16724  if(!(SearchVector.at(x).EntryExitNumber()))
16725  {
16726  throw Exception("Error in EntryExitNumber 3");
16727  }
16728  SearchVector.at(x).CheckCount++;
16729 // all values now incorporated
16730  }
16731 
16732  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
16733 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
16734 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
16735  Utilities->CallLogPop(305);
16736 }
16737 
16738 // ---------------------------------------------------------------------------
16739 
16741 
16742 /*
16743  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
16744  AutoSigsRoute.
16745  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
16746  beginning or the end.
16747  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
16748  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
16749  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
16750  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
16751  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
16752  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
16753  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
16754 
16755  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
16756  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
16757  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
16758  route at the start.
16759 
16760  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
16761  for the new route and return.
16762 */
16763 
16764 {
16765  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
16766  AnsiString(ReqPosRouteID.GetInt()));
16767  if(SearchVector.size() < 1)
16768  {
16769  Utilities->CallLogPop(306);
16770  return;
16771  }
16772  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
16773  if(!ValidatePrefDir(6))
16774  {
16775  Utilities->CallLogPop(307);
16776  return;
16777  }
16778  TAllRoutes::TLockedRouteClass LockedRouteObject;
16779 
16781  unsigned int TruncatePrefDirPosition = 0;
16782 
16783  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
16784 /* if have ReqPosRouteID:
16785  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
16786  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16787  then enter the new route into the AllRoutesVector
16788 */
16789  {
16791  {
16792  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
16793  x++) // start at 1 as first element already in SearchVector
16794  {
16796  }
16797  // note that route numbers in map adjusted when ReqPos route cleared
16799  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
16800  // set during ClearRouteDuringRouteBuildingAt)
16802  {
16805  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
16806  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
16807  }
16808  }
16810  {
16811  SearchVector.pop_back();
16812  }
16813  }
16814  if(StartSelectionRouteID > -1)
16815 /* if have StartSelectionRouteID:
16816  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
16817  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16818 */
16819  {
16821  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
16822  {
16824  {
16825  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
16826  for(unsigned int x = 0; x < SearchVector.size(); x++)
16827  {
16829  RouteNumber, GetFixedSearchElementAt(7, x));
16830  // find & store locked route truncate position in PrefDirVector for later use
16832  {
16833  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
16834  {
16835  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
16836  }
16837  }
16838  }
16840  {
16841  throw Exception("Failed to validate extended route for nonpreferred route");
16842  }
16845  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
16846  // now add the reinstated locked route if required and set signals accordingly
16847  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
16848  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
16849  // that I haven't thought of
16851  {
16852  LockedRouteObject.RouteNumber = RouteNumber;
16853  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16854  // now reset the signals for the locked route
16855  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
16856  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16857  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16858  {
16859  // return all signals to red in route section to be truncated
16860  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
16861  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
16862  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16863  {
16864  TrackElement.Attribute = 0;
16865  Track->PlotSignal(11, TrackElement, Display);
16866  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16867  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16868  }
16869  }
16870  }
16871  AllRoutes->CheckMapAndRoutes(3); // test
16872  Utilities->CallLogPop(308);
16873  return;
16874  }
16875  }
16876  else
16877  {
16879  }
16880 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16881 // hence nothing to do here
16882  }
16883  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
16884  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
16885  {
16886  throw Exception("Failed to validate single route for nonpreferred route");
16887  }
16888  AllRoutes->StoreOneRoute(2, this);
16889  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
16890  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
16891  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
16892  AllRoutes->CheckMapAndRoutes(4); // test
16893  Utilities->CallLogPop(309);
16894 }
16895 
16896 // ---------------------------------------------------------------------------
16897 
16898 void TOneRoute::SetRoutePoints(int Caller) const
16899 /*
16900  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
16901  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
16902  when they were created.
16903 */
16904 {
16905  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
16906  if(!PrefDirVector.empty())
16907  {
16908  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
16909  {
16910  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) // 1=straight trailing
16911  {
16912  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
16913  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
16914  }
16915  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) // 3=diverging trailing
16916  {
16917  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
16918  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
16919  }
16920  }
16921  }
16922  Utilities->CallLogPop(327);
16923 }
16924 
16925 // ---------------------------------------------------------------------------
16926 
16927 void TOneRoute::SetRouteSignals(int Caller) const
16928 /* Used for new train additions in AddTrain and in route setting
16929  Set the signals as follows:-
16930  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
16931  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
16932  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
16933  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
16934  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
16935  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
16936  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
16937  of the foregoing are found but there is a further forward linked forward route then the function returns false with
16938  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
16939 
16940  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
16941  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
16942  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
16943  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
16944  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
16945  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
16946  as a green signal.
16947 */
16948 {
16949  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
16950  if(!PrefDirVector.empty())
16951  {
16952  // get target Attribute value, check first if there is a forward linked route
16953  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
16954  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
16955  int ForwardLinkedRouteNumber, Attribute = 0;
16956  if(LastElement.Conn[LastElement.XLinkPos] > -1)
16957  // Note that LastElement can't be points but can be linked to points
16958  {
16959  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
16960  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16961  {
16962  if(ForwardLinkedRouteNumber > -1)
16963  {
16964  int NextForwardLinkedRouteNumber = -1;
16965  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
16966  Attribute)))
16967  {
16968  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
16969  }
16970  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
16971  // Attribute = 3, else if find signal then Attribute = (signal attribute + 1) up to a max value of 3. All these return true, if find a
16972  // forward linked route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
16973  }
16974  }
16975  }
16976  int RouteNumber;
16977  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
16978  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
16979  if(RouteType != TAllRoutes::NoRoute)
16980  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
16981  {
16982  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
16983  }
16984  }
16985  Utilities->CallLogPop(1720);
16986 }
16987 
16988 // ---------------------------------------------------------------------------
16989 
16990 bool TOneRoute::PointsToBeChanged(int Caller) const
16991 {
16992  // true if at any point in SearchVector points have to be changed
16993  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
16994  if(!SearchVector.empty())
16995  {
16996  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
16997  {
16998  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=straight trailing
16999  {
17000  if(Track->TrackElementAt(752, SearchPtr->TrackVectorPosition).Attribute != 0) // 0=straight or LH
17001  {
17002  Utilities->CallLogPop(1717);
17003  return(true);
17004  }
17005  }
17006  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=diverging trailing
17007  {
17008  if(Track->TrackElementAt(753, SearchPtr->TrackVectorPosition).Attribute != 1) // 1=diverging or RH
17009  {
17010  Utilities->CallLogPop(1718);
17011  return(true);
17012  }
17013  }
17014  }
17015  }
17016  Utilities->CallLogPop(1719);
17017  return(false);
17018 }
17019 
17020 // ---------------------------------------------------------------------------
17021 
17022 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
17023 /*
17024  Works forward through the route until finds:-
17025  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
17026  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
17027  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
17028  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
17029  (e) forward-facing signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true;
17030  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 &
17031  returns true;
17032  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
17033 */
17034 {
17035  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
17036  Attribute = 0;
17037  NextForwardLinkedRouteNumber = -1;
17038  for(unsigned int x = 0; x < PrefDirSize(); x++)
17039  {
17040  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
17041  if(PrefDirVector.at(x).TrackType == Bridge)
17042  {
17043  if(PrefDirVector.at(x).XLinkPos < 2)
17044  {
17045  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
17046  }
17047  else
17048  {
17049  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
17050  }
17051  }
17052  if(TrainID != -1)
17053  {
17054  Utilities->CallLogPop(328);
17055  return(true);
17056  }
17057  if(PrefDirVector.at(x).TrackType == Buffers)
17058  {
17059  Attribute = 1;
17060  Utilities->CallLogPop(329);
17061  return(true);
17062  }
17063  if(PrefDirVector.at(x).TrackType == Continuation)
17064  {
17065  Attribute = 3;
17066  Utilities->CallLogPop(330);
17067  return(true);
17068  }
17069  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
17070  {
17071  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
17072  {
17073  Attribute = 0;
17074  Utilities->CallLogPop(1950);
17075  return(true);
17076  }
17077  }
17078  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
17079  {
17080  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute + 1;
17081  if(Attribute > 3)
17082  {
17083  Attribute = 3;
17084  }
17085  Utilities->CallLogPop(331);
17086  return(true);
17087  }
17088  if(x == PrefDirSize() - 1)
17089  {
17090  TPrefDirElement LastElement = PrefDirVector.at(x);
17091  if(LastElement.Conn[LastElement.XLinkPos] > -1)
17092  {
17093  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
17094  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
17095  {
17096  Attribute = 0;
17097  Utilities->CallLogPop(332);
17098  return(false);
17099  }
17100  }
17101  }
17102  }
17103  Utilities->CallLogPop(333);
17104  return(true);
17105 }
17106 
17107 // ---------------------------------------------------------------------------
17108 
17109 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
17110 /*
17111  This function is only called by TAllRoutes::SetAllRearwardsSignals.
17112 
17113  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
17114  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
17115  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
17116  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
17117  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
17118  a route.
17119 
17120  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
17121  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
17122  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
17123  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working
17124  backwards for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
17125  reference. If no train is found before the beginning of the route is reached the function returns true
17126 
17127  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
17128  and the next rearwards signal becomes yellow, although it's the first in the route
17129 */
17130 {
17131  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
17132  AnsiString(PrefDirVectorStartPosition));
17133  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
17134  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
17135 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
17136 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
17137  bool SkipContinuationAndBufferAttributeChange = false;
17138 
17139  if(!PrefDirVector.empty())
17140  {
17141  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
17142  {
17143  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
17144  if(PrefDirPtr->TrackType == Bridge)
17145  {
17146  if(PrefDirPtr->XLinkPos < 2)
17147  {
17148  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
17149  }
17150  else
17151  {
17152  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
17153  }
17154  }
17155  if(TrainID != -1)
17156  {
17157  SkipContinuationAndBufferAttributeChange = true;
17158  break;
17159  }
17160  }
17161 
17164  {
17165  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
17166  AutoSigVectorIT++)
17167  {
17168  if(!AllRoutes->AllRoutesVector.empty())
17169  {
17170  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
17171  {
17172  SkipContinuationAndBufferAttributeChange = true;
17173  break;
17174  }
17175  }
17176  }
17177  }
17179  {
17180  SkipContinuationAndBufferAttributeChange = true;
17181  }
17182  if(!SkipContinuationAndBufferAttributeChange)
17183  {
17184  if(PrefDirVector.back().TrackType == Buffers)
17185  {
17186  Attribute = 1; // treat buffer as red signal
17187  }
17188  if(PrefDirVector.back().TrackType == Continuation)
17189  {
17190  Attribute = 3; // treat continuation as a green signal
17191  }
17192  }
17193  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17194  {
17195  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
17196  if(PrefDirPtr->TrackType == Bridge)
17197  {
17198  if(PrefDirPtr->XLinkPos < 2)
17199  {
17200  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
17201  }
17202  else
17203  {
17204  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
17205  }
17206  }
17207  if(TrainID != -1)
17208  {
17209  Utilities->CallLogPop(334);
17210  return(false);
17211  }
17212  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
17213  // the attribute to 0 so first signal behind the LC is red
17214  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17215  {
17216  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17217  {
17218  Attribute = 0;
17219  }
17220  }
17221 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
17222 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
17223  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
17224  {
17225  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
17226  PrefDirPtr->PrefDirRoute)
17227  {
17228 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
17229 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
17230  int LockedVecNum = 0; //not used
17231  TPrefDirElement DummyPrefDir; //not used
17232  bool KeepAttributeAt0ForLockedRoute = false;
17233  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
17234  LockedVecNum))
17235  {
17236  Attribute = 0;
17237  KeepAttributeAt0ForLockedRoute = true;
17238  }
17239 //end of addition
17240  if(Attribute < 3)
17241  {
17242  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
17243  }
17244  else
17245  {
17246  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
17247  }
17248  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
17249  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
17250  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
17251  {
17252  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17253  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
17254  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17255  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
17256  }
17257  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute)
17258  {
17259  Attribute++;
17260  }
17261  Display->Update(); // update after recent plots
17262  }
17263  }
17264  }
17265  }
17266  Utilities->CallLogPop(335);
17267  return(true);
17268 }
17269 
17270 // ---------------------------------------------------------------------------
17271 
17272 void TOneRoute::GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
17273 /*
17274  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
17275  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
17276  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
17277  Selection invalid if select a bridge; trying to leave a single element; last element to be left
17278  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
17279  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
17280  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
17281  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
17282 */
17283 {
17284  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
17285  "," + AnsiString((short)PrefDirRoute));
17286  bool ElementInRoute = false;
17287  bool TrainOccupyingRoute = false;
17288 
17289  for(unsigned int b = 0; b < PrefDirSize(); b++)
17290  {
17291  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17292  {
17293  ElementInRoute = true;
17294  break;
17295  }
17296  }
17297  if(!ElementInRoute)
17298  {
17299  ReturnFlag = NotInRoute;
17300  Utilities->CallLogPop(336);
17301  return;
17302  }
17303 // it is in the route so continue, first look for a train or a flashing level crossing
17304  for(int b = PrefDirSize() - 1; b >= 0; b--)
17305  {
17306  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
17307  if(PrefDirVector.at(b).TrackType == Bridge)
17308  {
17309  if(PrefDirVector.at(b).XLinkPos < 2)
17310  {
17311  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
17312  }
17313  else
17314  {
17315  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
17316  }
17317  }
17318  if(TrainID != -1)
17319  {
17320 // TrainController->StopTTClockMessage(56, "Can't truncate a route that is occupied by a train");
17321 // ReturnFlag = InRouteFalse;
17322 // Utilities->CallLogPop(337);
17323 // return;
17324 // above removed at v2.1.0 so that routes can be locked when occupied, below added
17325  TrainOccupyingRoute = true; // train is forward of the truncate point
17326  }
17327  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
17328  {
17329  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
17330  ReturnFlag = InRouteFalse;
17331  Utilities->CallLogPop(1941);
17332  return;
17333  }
17334  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17335  {
17336  break; // OK found truncate element & no flashing LC in front
17337  }
17338  }
17339 
17340  for(unsigned int b = 0; b < PrefDirSize(); b++)
17341  {
17342  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc)) // b = the truncate point
17343  {
17344  if(PrefDirVector.at(b).TrackType == Bridge)
17345  {
17346  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncate point");
17347  ReturnFlag = InRouteFalse;
17348  Utilities->CallLogPop(338);
17349  return;
17350  }
17351  if(b == 1)
17352  {
17353  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
17354  ReturnFlag = InRouteFalse;
17355  Utilities->CallLogPop(339);
17356  return;
17357  }
17358  if(b > 0)
17359  {
17360  TPrefDirElement TempElement = PrefDirVector.at(b - 1);
17361  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
17362  {
17363  if(TempElement.Config[TempElement.XLinkPos] != Signal)
17364  {
17365  TrainController->StopTTClockMessage(59, "Must truncate to a valid signal - select position after signal");
17366  ReturnFlag = InRouteFalse;
17367  Utilities->CallLogPop(340);
17368  return;
17369  }
17370  }
17371  else
17372  {
17373  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
17374  {
17375  TrainController->StopTTClockMessage(60, "Can't truncate to points, bridge or crossover");
17376  ReturnFlag = InRouteFalse;
17377  Utilities->CallLogPop(341);
17378  return;
17379  }
17380  }
17381  }
17382  int RouteNumber;
17384 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
17385 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
17386 
17387 // check if part of this route already locked & disallow if so
17388  if(!(AllRoutes->LockedRouteVector.empty()))
17389  {
17391  {
17392  if(LRVIT->RouteNumber == RouteNumber)
17393  {
17394  TrainController->StopTTClockMessage(61, "Can't truncate a route that is already part-locked");
17395  ReturnFlag = InRouteFalse;
17396  Utilities->CallLogPop(749);
17397  return;
17398  }
17399  }
17400  }
17401  if(AllRoutes->RouteLockingRequired(0, RouteNumber, b) || TrainOccupyingRoute) // added TrainOccupyingRoute at v2.1.0,
17402  // RouteLockingRequired only checks for trains approaching
17403  {
17406  int button = Application->MessageBox(L"Train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
17407  L"Warning!", MB_YESNO | MB_ICONWARNING);
17408  TrainController->BaseTime = TDateTime::CurrentDateTime();
17410  if(button == IDNO)
17411  {
17412  ReturnFlag = InRouteTrue; // still return true even though don't act on it
17413  Utilities->CallLogPop(342);
17414  return;
17415  }
17416  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(b).TrackVectorPosition).ElementID);
17417  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
17418  TAllRoutes::TLockedRouteClass LockedRoute;
17419  bool ExistingLockedRouteModified = false;
17420  LockedRoute.RouteNumber = RouteNumber;
17421  LockedRoute.TruncateTrackVectorPosition = PrefDirVector.at(b).TrackVectorPosition;
17422  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
17423  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
17424  LockedRoute.LockStartTime = TrainController->TTClockTime;
17425 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
17426 // to use the new TruncateTrackVectorPosition & LockStartTime
17427  if(!AllRoutes->LockedRouteVector.empty())
17428  {
17429  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
17430  LRVIT++)
17431  {
17432  if(LRVIT->RouteNumber == RouteNumber)
17433  {
17434  LRVIT->TruncateTrackVectorPosition = LockedRoute.TruncateTrackVectorPosition;
17435  LRVIT->LockStartTime = LockedRoute.LockStartTime;
17436  ExistingLockedRouteModified = true;
17437  }
17438  }
17439  }
17440  if(!ExistingLockedRouteModified)
17441  {
17442  AllRoutes->LockedRouteVector.push_back(LockedRoute);
17443  }
17444  AllRoutes->SetAllRearwardsSignals(2, 0, RouteNumber, b);
17445  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17446  {
17447  // return all signals to red in route section to be truncated
17448  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, RouteNumber).PrefDirVector.at(c);
17449  TTrackElement & TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
17450  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17451  {
17452  TrackElement.Attribute = 0;
17453  Track->PlotSignal(2, TrackElement, Display);
17454  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17455  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17456  }
17457  }
17458 // Display->Update();//not needed as Clearand... called on return from GetAllRoutesTruncateElement in InterfaceUnit
17459  ReturnFlag = InRouteTrue;
17460  }
17461  else
17462  {
17463  AllRoutes->SetAllRearwardsSignals(3, 0, RouteNumber, b);
17464  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17465  {
17466  AllRoutes->RemoveRouteElement(5, LastElementPtr(3)->HLoc, LastElementPtr(4)->VLoc, LastElementPtr(5)->ELink);
17467  ReturnFlag = InRouteTrue;
17468  }
17469  }
17470  AllRoutes->CheckMapAndRoutes(5); // test
17471  Utilities->CallLogPop(343);
17472  return;
17473  }
17474  }
17475  ReturnFlag = NotInRoute;
17476  Utilities->CallLogPop(344);
17477 }
17478 
17479 // ---------------------------------------------------------------------------
17481 /*
17482  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
17483  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
17484  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
17485  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
17486  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
17487  the route colours.
17488 */
17489 {
17490  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
17491  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
17493  int RouteNumber;
17494  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
17495  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
17496 
17497  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
17498  {
17499  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
17500  {
17501  if(PrefDirVector.at(x).TrackType == SignalPost)
17502  {
17503  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
17504  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
17505  }
17506  }
17507  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
17508 // already set all signals to red in route so start at start of route for further rearwards signal setting
17509  }
17510  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
17511  {
17512  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
17513  }
17514  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
17515  AllRoutes->CheckMapAndRoutes(9); // test
17516  TrainController->BaseTime = TDateTime::CurrentDateTime();
17518  Utilities->CallLogPop(345);
17519  return;
17520 }
17521 
17522 // ---------------------------------------------------------------------------
17523 
17524 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
17525 /*
17526  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
17527 */
17528 {
17529  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
17530  AnsiString((short)PrefDirRoute));
17531  if(SearchVector.empty())
17532  {
17533  Utilities->CallLogPop(1149);
17534  return;
17535  }
17536  for(unsigned int b = 0; b < SearchVector.size(); b++)
17537  {
17540  PrefDirRoute);
17541  }
17542  Utilities->CallLogPop(346);
17543 }
17544 
17545 // ---------------------------------------------------------------------------
17546 
17547 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
17548 /*
17549  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
17550  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
17551  TOneRoute.
17552 */
17553 {
17554  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteAndLCChangeValues," + AnsiString((short)AutoSigsFlag) + "," +
17555  AnsiString((short)PrefDirRoute));
17556  RouteFlash.RouteFlashVector.clear();
17557  TRouteFlashElement RouteFlashElement;
17558 
17559  for(unsigned int b = 0; b < SearchVector.size(); b++)
17560  {
17561  int H = GetFixedSearchElementAt(11, b).HLoc;
17562  int V = GetFixedSearchElementAt(12, b).VLoc;
17564  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
17565  RouteFlashElement.HLoc = H;
17566  RouteFlashElement.VLoc = V;
17568  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
17569  }
17570  Utilities->CallLogPop(348);
17571 }
17572 
17573 // ---------------------------------------------------------------------------
17574 
17575 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
17576 {
17577  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
17578  if(!PrefDirVector.empty())
17579  {
17580  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17581  {
17582  int H = PrefDirPtr->HLoc;
17583  int V = PrefDirPtr->VLoc;
17584  // check for any LCs that are closed to trains & set the flash values and store in the vector
17585  if(Track->IsLCAtHV(39, H, V))
17586  {
17587  if(Track->IsLCBarrierUpAtHV(0, H, V))
17588  {
17589  Track->LCChangeFlag = true;
17590  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
17591  CLC.HLoc = H;
17592  CLC.VLoc = V;
17594  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
17597  if(PrefDirRoute)
17598  {
17599  CLC.TypeOfRoute = 1;
17600  }
17601  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
17602  Track->ChangingLCVector.push_back(CLC);
17603  }
17604  }
17605  }
17606  }
17607  Utilities->CallLogPop(1948);
17608 }
17609 
17610 // ---------------------------------------------------------------------------
17611 
17613 /*
17614  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
17615  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
17616  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
17617  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
17618 */
17619 {
17620  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
17621  if(!OverlayPlotted)
17622  {
17623  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
17624  {
17625  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
17626  {
17627  continue;
17628  }
17629  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
17630  Display->Update();
17631  }
17632  OverlayPlotted = true;
17633  }
17634  Utilities->CallLogPop(349);
17635 }
17636 
17637 // ---------------------------------------------------------------------------
17638 
17640 /*
17641  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
17642  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
17643  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
17644  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
17645 */
17646 {
17647  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
17648  if(OverlayPlotted)
17649  {
17650  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
17651  {
17652  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
17653  {
17654  continue;
17655  }
17656  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
17657  Display->Update();
17658  }
17659  OverlayPlotted = false;
17660  }
17661  Utilities->CallLogPop(350);
17662 }
17663 
17664 // ---------------------------------------------------------------------------
17665 
17666 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
17667 {
17668  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
17669  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
17670  {
17671  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
17672  }
17673  Utilities->CallLogPop(120);
17674  return(AllRoutesVector.at(At));
17675 }
17676 
17677 // ---------------------------------------------------------------------------
17678 // ---------------------------------------------------------------------------
17679 
17681 {
17682  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
17683  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
17684  {
17685  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
17686  }
17687  Utilities->CallLogPop(121);
17688  return(AllRoutesVector.at(At));
17689 }
17690 
17691 // ---------------------------------------------------------------------------
17692 
17693 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
17694 /*
17695  Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
17696 */
17697 {
17698  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
17699  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17700  {
17701  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
17702  }
17703  Utilities->CallLogPop(351);
17704 }
17705 
17706 // ---------------------------------------------------------------------------
17707 
17708 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
17709 {
17710  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
17711  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17712  {
17713  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
17714  }
17715  Utilities->CallLogPop(1706);
17716 }
17717 
17718 // ---------------------------------------------------------------------------
17719 
17720 bool TAllRoutes::GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
17721 /*
17722  Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is present in
17723  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
17724  Messages are given in GetRouteTruncateElement. If successful the route is truncated at and including
17725  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
17726  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
17727  length (train length).
17728 */
17729 {
17730  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAllRoutesTruncateElement," + AnsiString(HLoc) + "," +
17731  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
17732  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17733  {
17734  TTruncateReturnType ReturnFlag;
17735  RouteTruncateFlag = true;
17736 // used in SetRearwardsSignalsReturnFalseForTrain (called by GetRouteTruncateElement) to skip continuation & buffer attribute change
17737  GetModifiableRouteAt(7, a).GetRouteTruncateElement(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
17738  RouteTruncateFlag = false;
17739  if(ReturnFlag == NotInRoute)
17740  {
17741  continue;
17742  }
17743  else if(ReturnFlag == InRouteTrue)
17744  {
17745  Utilities->CallLogPop(352);
17746  return(true);
17747  }
17748  else if(ReturnFlag == InRouteFalse)
17749  {
17750  Utilities->CallLogPop(353);
17751  return(false);
17752  }
17753  }
17754  Utilities->CallLogPop(354);
17755  return(false);
17756 }
17757 
17758 // ---------------------------------------------------------------------------
17759 
17760 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
17761 /*
17762  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
17763  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
17764 */
17765 {
17766  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
17767  AnsiString(LinkPos));
17768  if(TrackVectorPosition == -1) // allows for continuation entries & exits
17769  {
17770  Utilities->CallLogPop(355);
17771  return(false);
17772  }
17773  THVPair Route2MultiMapKeyPair;
17774 
17775  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
17776  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
17777  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17778  TRoute2MultiMapIterator Route2MultiMapIterator;
17779 
17780  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
17781  {
17782  Utilities->CallLogPop(356);
17783  return(false);
17784  }
17785  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
17786  {
17787  Utilities->CallLogPop(1422);
17788  return(true);
17789  }
17790  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17791  {
17792  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17793 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17794 // realised after writing this that can't be points as would have been covered above, but leave anyway
17795  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
17796  Route2MultiMapIterator->second.second);
17797  EntryLinkPos = PrefDirElement1.ELinkPos;
17798  ExitLinkPos = PrefDirElement1.XLinkPos;
17799  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17800  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17801  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
17802  {
17803  Utilities->CallLogPop(357);
17804  return(true);
17805  }
17806  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
17807  {
17808  Utilities->CallLogPop(358);
17809  return(true);
17810  }
17811  }
17812  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
17813  {
17814  Utilities->CallLogPop(1423);
17815  return(true);
17816  }
17817  Utilities->CallLogPop(363);
17818  return(false); // none found
17819 }
17820 
17821 // ---------------------------------------------------------------------------
17822 
17823 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
17824  Graphics::TBitmap* &EntryDirectionGraphicPtr)
17825 /*
17826  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
17827  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
17828  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
17829  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
17830  for replotting of AutoSigsRoutes.
17831 */
17832 {
17833  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
17834  AnsiString(LinkPos));
17835  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
17836  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
17837  if(TrackVectorPosition == -1)
17838  {
17839  Utilities->CallLogPop(364);
17840  return(NoRoute); // allows for continuation entries & exits
17841  }
17842  THVPair Route2MultiMapKeyPair;
17843 
17844  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
17845  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
17846  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17847  TRoute2MultiMapIterator Route2MultiMapIterator;
17848 
17849  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
17850  {
17851  Utilities->CallLogPop(365);
17852  return(NoRoute); // none found
17853  }
17854  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17855  {
17856  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17857 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17858  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
17859  Route2MultiMapIterator->second.second);
17860  EntryLinkPos = PrefDirElement1.ELinkPos;
17861  ExitLinkPos = PrefDirElement1.XLinkPos;
17862  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17863  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17864  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
17865  {
17866  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
17867  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
17868  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
17869  {
17870  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
17871  }
17872  if(PrefDirElement1.AutoSignals)
17873  {
17874  Utilities->CallLogPop(366);
17875  return(AutoSigsRoute);
17876  }
17877  else
17878  {
17879  Utilities->CallLogPop(367);
17880  return(NotAutoSigsRoute);
17881  }
17882  }
17883  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
17884  {
17885  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
17886  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
17887  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
17888  {
17889  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
17890  }
17891  if(PrefDirElement1.AutoSignals)
17892  {
17893  Utilities->CallLogPop(368);
17894  return(AutoSigsRoute);
17895  }
17896  else
17897  {
17898  Utilities->CallLogPop(369);
17899  return(NotAutoSigsRoute);
17900  }
17901  }
17902  }
17903  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
17904  {
17905  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17906  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17907 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17908  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
17909  EntryLinkPos = PrefDirElement2.ELinkPos;
17910  ExitLinkPos = PrefDirElement2.XLinkPos;
17911  EntryLink = PrefDirElement2.Link[EntryLinkPos];
17912  ExitLink = PrefDirElement2.Link[ExitLinkPos];
17913  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
17914  {
17915  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
17916  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
17917  {
17918  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
17919  }
17920  if(PrefDirElement2.AutoSignals)
17921  {
17922  Utilities->CallLogPop(370);
17923  return(AutoSigsRoute);
17924  }
17925  else
17926  {
17927  Utilities->CallLogPop(371);
17928  return(NotAutoSigsRoute);
17929  }
17930  }
17931  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
17932  {
17933  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
17934  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
17935  {
17936  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
17937  }
17938  if(PrefDirElement2.AutoSignals)
17939  {
17940  Utilities->CallLogPop(372);
17941  return(AutoSigsRoute);
17942  }
17943  else
17944  {
17945  Utilities->CallLogPop(373);
17946  return(NotAutoSigsRoute);
17947  }
17948  }
17949  ItPair.second--; // the second iterator points one past the last matching value
17950  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
17951  EntryLinkPos = PrefDirElement3.ELinkPos;
17952  ExitLinkPos = PrefDirElement3.XLinkPos;
17953  EntryLink = PrefDirElement3.Link[EntryLinkPos];
17954  ExitLink = PrefDirElement3.Link[ExitLinkPos];
17955  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
17956  {
17957  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
17958  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
17959  {
17960  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
17961  }
17962  if(PrefDirElement3.AutoSignals)
17963  {
17964  Utilities->CallLogPop(374);
17965  return(AutoSigsRoute);
17966  }
17967  else
17968  {
17969  Utilities->CallLogPop(375);
17970  return(NotAutoSigsRoute);
17971  }
17972  }
17973  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
17974  {
17975  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
17976  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
17977  {
17978  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
17979  }
17980  if(PrefDirElement3.AutoSignals)
17981  {
17982  Utilities->CallLogPop(376);
17983  return(AutoSigsRoute);
17984  }
17985  else
17986  {
17987  Utilities->CallLogPop(377);
17988  return(NotAutoSigsRoute);
17989  }
17990  }
17991  }
17992  Utilities->CallLogPop(378);
17993  return(NoRoute); // none found
17994 }
17995 
17996 // ---------------------------------------------------------------------------
17997 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
17998 /*
17999  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
18000  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
18001 */
18002 {
18003  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
18004  AnsiString(LinkPos));
18005  if(TrackVectorPosition == -1)
18006  {
18007  RouteNumber = -1;
18008  Utilities->CallLogPop(379);
18009  return(NoRoute); // allows for continuation & buffer entries & exits
18010  }
18011  THVPair Route2MultiMapKeyPair;
18012 
18013  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
18014  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
18015  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
18016  TRoute2MultiMapIterator Route2MultiMapIterator;
18017 
18018  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
18019  {
18020  RouteNumber = -1;
18021  Utilities->CallLogPop(380);
18022  return(NoRoute); // none found
18023  }
18024  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18025  {
18026  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18027 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18028  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
18029  Route2MultiMapIterator->second.second);
18030  EntryLinkPos = PrefDirElement1.ELinkPos;
18031  ExitLinkPos = PrefDirElement1.XLinkPos;
18032  EntryLink = PrefDirElement1.Link[EntryLinkPos];
18033  ExitLink = PrefDirElement1.Link[ExitLinkPos];
18034  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
18035  {
18036  RouteNumber = Route2MultiMapIterator->second.first;
18037  if(PrefDirElement1.AutoSignals)
18038  {
18039  Utilities->CallLogPop(381);
18040  return(AutoSigsRoute);
18041  }
18042  else
18043  {
18044  Utilities->CallLogPop(382);
18045  return(NotAutoSigsRoute);
18046  }
18047  }
18048  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
18049  {
18050  RouteNumber = Route2MultiMapIterator->second.first;
18051  if(PrefDirElement1.AutoSignals)
18052  {
18053  Utilities->CallLogPop(383);
18054  return(AutoSigsRoute);
18055  }
18056  else
18057  {
18058  Utilities->CallLogPop(384);
18059  return(NotAutoSigsRoute);
18060  }
18061  }
18062  }
18063  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
18064  {
18065  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18066  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18067 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
18068  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
18069  EntryLinkPos = PrefDirElement2.ELinkPos;
18070  ExitLinkPos = PrefDirElement2.XLinkPos;
18071  EntryLink = PrefDirElement2.Link[EntryLinkPos];
18072  ExitLink = PrefDirElement2.Link[ExitLinkPos];
18073  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
18074  {
18075  RouteNumber = ItPair.first->second.first;
18076  if(PrefDirElement2.AutoSignals)
18077  {
18078  Utilities->CallLogPop(385);
18079  return(AutoSigsRoute);
18080  }
18081  else
18082  {
18083  Utilities->CallLogPop(386);
18084  return(NotAutoSigsRoute);
18085  }
18086  }
18087  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
18088  {
18089  RouteNumber = ItPair.first->second.first;
18090  if(PrefDirElement2.AutoSignals)
18091  {
18092  Utilities->CallLogPop(387);
18093  return(AutoSigsRoute);
18094  }
18095  else
18096  {
18097  Utilities->CallLogPop(388);
18098  return(NotAutoSigsRoute);
18099  }
18100  }
18101  ItPair.second--; // the second iterator points one past the last matching value
18102  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
18103  EntryLinkPos = PrefDirElement3.ELinkPos;
18104  ExitLinkPos = PrefDirElement3.XLinkPos;
18105  EntryLink = PrefDirElement3.Link[EntryLinkPos];
18106  ExitLink = PrefDirElement3.Link[ExitLinkPos];
18107  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
18108  {
18109  RouteNumber = ItPair.second->second.first;
18110  if(PrefDirElement3.AutoSignals)
18111  {
18112  Utilities->CallLogPop(389);
18113  return(AutoSigsRoute);
18114  }
18115  else
18116  {
18117  Utilities->CallLogPop(390);
18118  return(NotAutoSigsRoute);
18119  }
18120  }
18121  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
18122  {
18123  RouteNumber = ItPair.second->second.first;
18124  if(PrefDirElement3.AutoSignals)
18125  {
18126  Utilities->CallLogPop(391);
18127  return(AutoSigsRoute);
18128  }
18129  else
18130  {
18131  Utilities->CallLogPop(392);
18132  return(NotAutoSigsRoute);
18133  }
18134  }
18135  }
18136  RouteNumber = -1;
18137  Utilities->CallLogPop(393);
18138  return(NoRoute); // none found
18139 }
18140 
18141 // ---------------------------------------------------------------------------
18142 
18143 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
18144 /*
18145  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
18146  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
18147  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
18148  and Route2MultiMap.
18149 */
18150 {
18151  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
18152  TOneRoute EmptyRoute;
18153 
18154  EmptyRoute.RouteID = NextRouteID;
18155  NextRouteID++;
18156 
18157  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
18158  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
18159  {
18160  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
18161  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
18162  }
18163  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
18164  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
18165 
18166  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
18167  Utilities->CallLogPop(394);
18168 }
18169 
18170 // ---------------------------------------------------------------------------
18171 
18173 /*
18174  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
18175  that is already in Route is used.
18176 */
18177 {
18178  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
18179  TOneRoute EmptyRoute;
18180 
18181  EmptyRoute.RouteID = Route->RouteID;
18182 
18183  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
18184  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
18185  {
18186  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
18187  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
18188  }
18189  Utilities->CallLogPop(1579);
18190 }
18191 
18192 // ---------------------------------------------------------------------------
18193 
18194 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
18195 /*
18196  When attaching a new route section to an existing route, it is sometimes necessary to erase the
18197  original route and create a new composite route. This function Erases all elements in the route
18198  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
18199  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
18200  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
18201  that are greater than the route number that is removed. The LockedRouteVector as also searched
18202  and if any relate to the route that has been cleared they are erased too, but the fact that one
18203  has been found is recorded so that it can be re-established later.
18204 */
18205 {
18206  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
18207  THVPair Route2MultiMapKeyPair;
18208  TRoute2MultiMapEntry Route2MultiMapEntry;
18209  TRoute2MultiMapIterator Route2MultiMapIterator;
18210 
18211 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
18212 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
18213 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
18214 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
18215 // If so the locked route is removed from the locked vector and is lost.
18216  LockedRouteTruncateTrackVectorPosition = 0;
18217  LockedRouteLastTrackVectorPosition = 0;
18218  LockedRouteLastXLinkPos = 0;
18219  LockedRouteLockStartTime = TDateTime(0);
18220  if(!LockedRouteVector.empty())
18221  {
18222  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18223  {
18224  if(LRVIT->RouteNumber == RouteNumber)
18225  {
18226  LockedRouteTruncateTrackVectorPosition = LRVIT->TruncateTrackVectorPosition;
18227  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
18228  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
18229  LockedRouteLockStartTime = LRVIT->LockStartTime;
18230  LockedRouteFoundDuringRouteBuilding = true;
18231  LockedRouteVector.erase(LRVIT);
18232  }
18233  }
18234  }
18235  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
18236  {
18237  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
18238  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
18239  }
18240  Utilities->CallLogPop(395);
18241 }
18242 
18243 // ---------------------------------------------------------------------------
18244 
18246  TRoute2MultiMapIterator &Route2MultiMapIterator)
18247 /*
18248  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
18249  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
18250  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
18251  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
18252  are given for failure.
18253 */
18254 {
18255  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
18256  AnsiString(VLoc) + "," + AnsiString(ELink));
18257  TRouteElementPair ReturnPair;
18258 
18259  ReturnPair.first = -1;
18260  ReturnPair.second = 0;
18261  THVPair Route2MultiMapKeyPair;
18262 
18263  Route2MultiMapKeyPair.first = HLoc;
18264  Route2MultiMapKeyPair.second = VLoc;
18265  TRoute2MultiMapEntry Route2MultiMapEntry;
18266 
18267  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
18268  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18269 
18270  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18271  Route2MultiMapIterator = ItPair.first;
18272 
18273  if(ItPair.first == ItPair.second)
18274  {
18275  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
18276  }
18277  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
18278  {
18279  ReturnPair.first = ItPair.first->second.first;
18280  ReturnPair.second = ItPair.first->second.second;
18281  Route2MultiMapIterator = ItPair.first;
18282  Utilities->CallLogPop(396);
18283  return(ReturnPair);
18284  }
18285  ItPair.first++;
18286  if(ItPair.first == ItPair.second)
18287  {
18288  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
18289  }
18290  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
18291  {
18292  ReturnPair.first = ItPair.first->second.first;
18293  ReturnPair.second = ItPair.first->second.second;
18294  Route2MultiMapIterator = ItPair.first;
18295  Utilities->CallLogPop(397);
18296  return(ReturnPair);
18297  }
18298  Utilities->CallLogPop(398);
18299  return(ReturnPair);
18300 }
18301 
18302 // ---------------------------------------------------------------------------
18303 
18304 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
18305 /*
18306  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
18307  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
18308  RouteNumber (route position in AllRoutes vector is returned as a reference.
18309  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
18310  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
18311 */
18312 {
18313  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
18314  AnsiString(VLoc) + "," + AnsiString(ELink));
18315  THVPair Route2MultiMapKeyPair;
18316 
18317  Route2MultiMapKeyPair.first = HLoc;
18318  Route2MultiMapKeyPair.second = VLoc;
18319  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18320 
18321  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18322 
18323  if(ItPair.first == ItPair.second)
18324  {
18325  RouteNumber = -1;
18326  Utilities->CallLogPop(2032);
18327  return(false);
18328  }
18329  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
18330  {
18331  RouteNumber = ItPair.first->second.first;
18332  Utilities->CallLogPop(2033);
18333  return(true);
18334  }
18335  ItPair.first++;
18336 
18337  if(ItPair.first == ItPair.second)
18338  {
18339  RouteNumber = -1;
18340  Utilities->CallLogPop(2034);
18341  return(false);
18342  }
18343  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
18344  {
18345  RouteNumber = ItPair.first->second.first;
18346  Utilities->CallLogPop(2035);
18347  return(true);
18348  }
18349  RouteNumber = -1;
18350  Utilities->CallLogPop(2036);
18351  return(false);
18352 }
18353 
18354 // ---------------------------------------------------------------------------
18355 
18356 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
18357 /*
18358  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
18359  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
18360  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
18361  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
18362  Called by TAllRoutes::AddRouteElement.
18363 */
18364 {
18365  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18366  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
18367  THVPair Route2MultiMapKeyPair;
18368 
18369  Route2MultiMapKeyPair.first = HLoc;
18370  Route2MultiMapKeyPair.second = VLoc;
18371  TRoute2MultiMapEntry Route2MultiMapEntry;
18372 
18373  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
18374  TRouteElementPair RouteElementPair;
18375 
18376  RouteElementPair.first = RouteNumber;
18377  RouteElementPair.second = RouteElementNumber;
18378  Route2MultiMapEntry.second = RouteElementPair;
18379 
18380  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
18381  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
18382  {
18383  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
18384  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
18385  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
18386  {
18387  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
18388  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
18389  {
18390  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
18391  }
18392  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
18393  }
18394  else
18395  // same ELink so have an error
18396  {
18397  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
18398  }
18399  }
18400  else
18401  {
18402  Route2MultiMap.insert(Route2MultiMapEntry);
18403  }
18404 // element at H&V not found in map so insert it
18405  Utilities->CallLogPop(399);
18406 }
18407 
18408 // ---------------------------------------------------------------------------
18409 
18411 /*
18412  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
18413  and the second in the reference SecondPair. If there's only one then it's the function return
18414 */
18415 {
18416  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
18417  AnsiString(VLoc));
18419 
18420  TempPair.first = -1;
18421  TempPair.second = 0;
18422  SecondPair = TempPair;
18423  TRoute2MultiMapIterator Route2MultiMapIterator;
18424  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
18425  THVPair Route2MultiMapKeyPair;
18426 
18427  Route2MultiMapKeyPair.first = HLoc;
18428  Route2MultiMapKeyPair.second = VLoc;
18429  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
18430  {
18431  Utilities->CallLogPop(400);
18432  return(TempPair);
18433  }
18434  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18435  {
18436  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18437  Utilities->CallLogPop(401);
18438  return(Route2MultiMapIterator->second);
18439  }
18440  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
18441  {
18442  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18443  TempPair = ItRange.first->second;
18444  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
18445  Utilities->CallLogPop(402);
18446  return(TempPair);
18447  }
18448  Utilities->CallLogPop(403);
18449  return(TempPair);
18450 }
18451 
18452 // ---------------------------------------------------------------------------
18453 
18454 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
18455 /*
18456  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
18457  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
18458 */
18459 {
18460  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
18461  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
18462  {
18463  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
18464  {
18465  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
18466  TAllRoutes::TRouteElementPair SecondPair;
18467  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
18468  if(RouteElementPair.first == -1)
18469  // failed to find element in multimap
18470  {
18471  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
18472  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
18473  }
18474  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
18475  // neither pair has expected route number
18476  {
18477  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
18478  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
18479  (AnsiString)Caller);
18480  }
18481  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
18482  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
18483  {
18484  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
18485  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
18486  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
18487  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
18488  }
18489  }
18490  }
18491  unsigned int SizeVal = 0;
18492 
18493 // check map and sum of route sizes match
18494  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18495  {
18496  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
18497  }
18498  if(SizeVal != Route2MultiMap.size())
18499  {
18500  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
18501  (AnsiString)Caller);
18502  }
18503  Utilities->CallLogPop(404);
18504  return;
18505 }
18506 
18507 // ---------------------------------------------------------------------------
18508 
18509 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
18510 /*
18511  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
18512  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
18513  exceed that for the erased route. Where this is so the RouteNumber is decremented.
18514 */
18515 {
18516  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
18517  if(!Route2MultiMap.empty())
18518  {
18519  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
18520  {
18521  if(Route2MultiMapIterator->second.first > RouteNumber)
18522  {
18523  Route2MultiMapIterator->second.first--;
18524  }
18525  }
18526  }
18527  Utilities->CallLogPop(405);
18528 }
18529 
18530 // ---------------------------------------------------------------------------
18531 
18532 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
18533 /*
18534  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
18535  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
18536  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
18537 */
18538 {
18539  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
18540  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
18541  if(!Route2MultiMap.empty())
18542  {
18543  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
18544  {
18545  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
18546  {
18547  Route2MultiMapIterator->second.second--;
18548  }
18549  }
18550  }
18551  Utilities->CallLogPop(406);
18552 }
18553 
18554 // ---------------------------------------------------------------------------
18555 
18556 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
18557 /*
18558  Erases the route element from Route2MultiMap and from the PrefDirVector.
18559  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
18560  decremented if they are greater than the element number removed, and if the entire route is removed
18561  then the route numbers are also decremented in the map for route numbers that are greater than the route
18562  number that is removed.
18563 */
18564 {
18565  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
18566  AnsiString(ELink));
18567  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
18568  TRoute2MultiMapIterator Route2MultiMapIterator;
18569 
18570  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
18571  if(RequiredRoutePair.first == -1)
18572  {
18573  throw Exception("Failed to find route element in RemoveRouteElement");
18574  }
18575  Route2MultiMap.erase(Route2MultiMapIterator);
18576  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
18577 
18578 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
18579  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
18580 
18581  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
18582  {
18583  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
18584  }
18585 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
18586 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
18587 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
18588 // to check if a route element is present, and the element has already been removed from the map - see above.
18589 
18590 // before erase the element check if it's in a locked route, and if so change the TruncateTrackVectorPosition to the next valid (XLinkPos] element position
18591 /*
18592  int LockedVectorNumber = -1;
18593  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
18594  {
18595  LockedRouteVector.at(LockedVectorNumber).TruncateTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
18596  }
18597 */
18598 
18599 // erase element from route
18600  GetModifiableRouteAt(8, RequiredRoutePair.first).EraseRouteElementAt(&(GetModifiableRouteAt(9, RequiredRoutePair.first).GetModifiablePrefDirElementAt(1,
18601  RequiredRoutePair.second)));
18602 // CheckMapAndRoutes();//test - drop - tested below
18603 
18604 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
18605 // be so as continuation exit is at the end of the route, and truncation is from the end
18607  {
18609  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
18610  AutoSigVectorIT--)
18611  {
18612  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
18613  {
18614  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
18615  }
18616  }
18617  }
18618 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
18619 // and adjust all the corresponding route numbers
18620  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
18621  {
18622  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
18623  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
18624  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
18625 
18626 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
18627  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
18628  it is erased then - see TInterface::ApproachLocking
18629 
18630  if(LockedVectorNumber > -1)
18631  {
18632  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
18633  }
18634 */
18635  // decrement route numbers in the locked route vector whether or not this route is a locked route
18636  if(!LockedRouteVector.empty())
18637  {
18638  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18639  {
18640  if(LRVIT->RouteNumber > RequiredRoutePair.first)
18641  {
18642  LRVIT->RouteNumber--;
18643  }
18644  }
18645  }
18647  {
18649  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
18650  AutoSigVectorIT--)
18651  {
18652  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
18653  {
18654  AutoSigVectorIT->RouteNumber--;
18655  }
18656  }
18657  }
18658  }
18659  CheckMapAndRoutes(7); // test
18660  Utilities->CallLogPop(407);
18661 }
18662 
18663 // ---------------------------------------------------------------------------
18664 
18665 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
18666 /*
18667  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
18668  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
18669  since that catches all route elements wherever created
18670 */
18671 {
18672  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
18673  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
18674  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
18675  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1);
18676  Utilities->CallLogPop(408);
18677 }
18678 
18679 // ---------------------------------------------------------------------------
18680 
18681 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
18682 /*
18683  Enter with signal at TrackVectorElement already set to red by the passing train.
18684  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
18685  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
18686  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
18687  case the function sets no further signals.
18688 */
18689 {
18690  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
18691  "," + AnsiString(XLinkPos));
18692  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
18693  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
18694 
18695  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
18696  if(RouteElementPair.first == -1)
18697  {
18698  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
18699  }
18700  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
18701 
18702  RequiredPair = RouteElementPair;
18703  if(RouteElement.XLinkPos != XLinkPos)
18704  {
18705  if(SecondPair.first != -1)
18706  {
18707  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
18708  RequiredPair = SecondPair;
18709  if(RouteElement.XLinkPos != XLinkPos)
18710  {
18711  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
18712  }
18713  }
18714  else
18715  {
18716  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
18717  }
18718  }
18719 // new function
18720  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
18721  Utilities->CallLogPop(409);
18722 }
18723 
18724 // ---------------------------------------------------------------------------
18725 
18726 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
18727 /*
18728  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
18729  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
18730  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
18731  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
18732  to 2 for successive calls.
18733  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
18734  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
18735  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
18736  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
18737 */
18738 {
18739  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
18740  AnsiString(AccessNumber));
18741  TPrefDirElement RouteElement;
18742  int Attribute = AccessNumber + 1;
18743 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
18744  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
18745 
18746  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
18747  {
18748  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
18749  }
18750  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
18751  {
18752  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
18753  }
18754  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
18755  x).XLinkPos] != End)
18756  {
18757  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
18758  }
18759 // new function
18760  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
18761  Utilities->CallLogPop(410);
18762 }
18763 
18764 // ---------------------------------------------------------------------------
18765 
18766 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
18767 /*
18768  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
18769  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
18770  or (b) in a linked rear route, in which case the function sets no further signals.
18771 
18772  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
18773  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
18774  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
18775  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
18776  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
18777  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
18778  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
18779  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
18780  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
18781  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
18782  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
18783  found behind the train.
18784 
18785  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
18786  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
18787  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
18788  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
18789  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
18790  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
18791  a route.
18792 
18793  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
18794  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
18795  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
18796  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working backwards
18797  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
18798  reference. If no train is found before the beginning of the route is reached the function returns true
18799 
18800 */
18801 {
18802  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
18803  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
18804  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
18805  int RearwardLinkedRouteNumber;
18806 
18807  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
18808  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
18809  // signal value in the route for use in further linked routes
18810  {
18811  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
18812  {
18813  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
18814  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
18815  {
18816  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
18817  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
18818  {
18819  break;
18820  }
18821  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
18822  // flash LCs on those routes
18823  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
18824  }
18825  }
18826  }
18827  else
18828  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
18829  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
18830  {
18831  int TrainID, TrainPosition, BehindTrainPosition;
18832  bool FoundTrain = false, BehindTrain = false;
18833  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
18834  {
18835  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
18836  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
18837  TrainID = TrackElement.TrainIDOnElement;
18838  if(TrackElement.TrackType == Bridge)
18839  {
18840  if(PrefDirElement.XLinkPos < 2)
18841  {
18842  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18843  }
18844  else
18845  {
18846  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18847  }
18848  }
18849  if(TrainID == -1)
18850  {
18851  continue;
18852  }
18853  else
18854  {
18855  FoundTrain = true;
18856  TrainPosition = x;
18857  break;
18858  }
18859  }
18860  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
18861  {
18862  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
18863  {
18864  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
18865  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
18866  // need the element behind the rearmost train.
18867  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
18868  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
18869  TrainID = TrackElement.TrainIDOnElement;
18870  if(TrackElement.TrackType == Bridge)
18871  {
18872  if(PrefDirElement.XLinkPos < 2)
18873  {
18874  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18875  }
18876  else
18877  {
18878  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18879  }
18880  }
18881  if(TrainID != -1)
18882  {
18883  continue; // still on train
18884  }
18885  else
18886  {
18887  BehindTrain = true;
18888  BehindTrainPosition = x;
18889  break;
18890  }
18891  }
18892  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
18893  // so on for as many trains as there are on the single route
18894  {
18895  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
18896  // first signal behind train to be red
18897  }
18898  }
18899  }
18900  Utilities->CallLogPop(411);
18901 }
18902 
18903 // ---------------------------------------------------------------------------
18904 
18905 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
18906 {
18907 /* Locked if a train moving in the direction of the route within 3 signals back from truncate point (on the route itself or any linked routes, or on the element
18908  immediately before the start of the route or linked route - this because train cancels route elements that it touches) unless
18909  first signal is red, then OK
18910 */
18911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
18912  AnsiString(RouteTruncatePosition));
18913  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber, StartPosition = RouteTruncatePosition;
18914  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
18915  TPrefDirElement PrefDirElement, FirstElement;
18916  TTrackElement TrackElement;
18917  bool ExamineRoute = true;
18918 
18919  while(ExamineRoute)
18920  {
18921  for(int x = StartPosition; x >= 0; x--) //work back along the route from the truncate point
18922  {
18923  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
18924  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
18925  TrainID = TrackElement.TrainIDOnElement;
18926  if(TrackElement.TrackType == Bridge)
18927  {
18928  if(PrefDirElement.XLinkPos < 2)
18929  {
18930  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18931  }
18932  else
18933  {
18934  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18935  }
18936  }
18937  if(TrainID > -1)
18938  {
18939  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
18940  {
18941  //any trains further back in route will be protected by the red signal behind the stopped train
18942  Utilities->CallLogPop(412);
18943  return(false);
18944  }
18945  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
18946  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
18947  //other way & can cancel the route
18948  {
18949  Utilities->CallLogPop(2203);
18950  return(false);
18951  }
18952  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
18953  return(true); //TrainOccupyingRoute which is outside this function but also causes route locking)
18954  }
18955  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
18956  {
18957  if(TrackElement.Attribute == 0)
18958  {
18959  Utilities->CallLogPop(413);
18960  return(false); // OK, red signal in front of a train
18961  }
18962  SignalCount++;
18963  if(SignalCount >= 3)
18964  {
18965  Utilities->CallLogPop(414);
18966  return(false);
18967  }
18968  }
18969  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
18970  // ElinkPos because working back along PrefDir to beginning
18971  {
18972  Utilities->CallLogPop(415);
18973  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
18974  }
18975  }
18976  //now look at linked rearwards routes
18977  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
18978  StartPosition = CurrentRoute.PrefDirSize() - 1;
18979  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
18980  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
18981  {
18982  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
18983  ExamineRoute = true;
18984  StartPosition = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
18985  }
18986  else
18987  {
18988  // here check for a train on the element immediately before the first route element
18989  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
18990  TrainID = PriorTrackElement.TrainIDOnElement;
18991  if(PriorTrackElement.TrackType == Bridge)
18992  {
18993  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
18994  {
18995  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos01;
18996  }
18997  else
18998  {
18999  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos23;
19000  }
19001  }
19002  if(TrainID > -1)
19003  {
19004  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
19005  {
19006  Utilities->CallLogPop(748);
19007  return(false);
19008  }
19009  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
19010  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
19011  //other way & can cancel the route
19012  {
19013  Utilities->CallLogPop(2204);
19014  return(false);
19015  }
19016  Utilities->CallLogPop(1962);
19017  return(true); //otherwise need to lock the route
19018  }
19019  ExamineRoute = false;
19020  }
19021  }
19022 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
19023 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
19024  Utilities->CallLogPop(416);
19025  return(false);
19026 }
19027 
19028 // ---------------------------------------------------------------------------
19029 
19030 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
19031  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
19032 {
19033  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
19034  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
19035  TPrefDirElement InternalPrefDirElement; // blank element
19036 
19037  PrefDirElement = InternalPrefDirElement;
19038  if(LockedRouteVector.empty())
19039  {
19040  Utilities->CallLogPop(417);
19041  return(false);
19042  }
19043 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
19044 // even if some elements have been removed from the front by a train
19045  bool InLockedRoute = false;
19046 
19047  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19048  {
19049  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
19050  {
19051  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
19052  // doesn't arise)
19053  InLockedRoute = true;
19054  break;
19055  }
19056  }
19057  if(!InLockedRoute)
19058  {
19059  Utilities->CallLogPop(418);
19060  return(false);
19061  }
19062  int RouteNumber, VectorCount = 0;
19063  TRouteType RouteType;
19064 
19065  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19066  {
19067  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
19068  if(RouteType == NoRoute)
19069  {
19070  continue;
19071  }
19072  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
19073  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
19074  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
19075  {
19076  throw Exception
19077  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
19078  }
19079  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
19080  {
19081  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
19082  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->TruncateTrackVectorPosition)
19083  {
19084  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
19085  {
19086  PrefDirElement = InternalPrefDirElement;
19087  LockedVectorNumber = VectorCount;
19088  Utilities->CallLogPop(419);
19089  return(true);
19090  }
19091  }
19092  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->TruncateTrackVectorPosition)
19093  {
19094  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
19095  {
19096  PrefDirElement = InternalPrefDirElement;
19097  LockedVectorNumber = VectorCount;
19098  Utilities->CallLogPop(420);
19099  return(true);
19100  }
19101  else
19102  {
19103  break; // reached & tested LRVIT->TruncateTrackVectorPosition for a match so don't want to go any further for this route
19104  }
19105  }
19106  }
19107  VectorCount++;
19108  }
19109  Utilities->CallLogPop(421);
19110  return(false);
19111 }
19112 
19113 // ---------------------------------------------------------------------------
19114 
19116 {
19117  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
19118  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19119  {
19120  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
19121  {
19122  Utilities->CallLogPop(963);
19123  return(x);
19124  }
19125  }
19126  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
19127 }
19128 
19129 // ---------------------------------------------------------------------------
19130 
19132 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
19133 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
19134 {
19135  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
19136  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19137  {
19138  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
19139  {
19140  Utilities->CallLogPop(2039);
19141  return(true);
19142  }
19143  }
19144  Utilities->CallLogPop(2040);
19145  return(false);
19146 }
19147 
19148 // ---------------------------------------------------------------------------
19149 
19151 {
19152  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
19153  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19154  {
19155  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
19156  {
19157  Utilities->CallLogPop(964);
19158  return(GetFixedRouteAt(159, x));
19159  }
19160  }
19161  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
19162 }
19163 
19164 // ---------------------------------------------------------------------------
19165 
19167 {
19168  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
19169  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19170  {
19171  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
19172  {
19173  Utilities->CallLogPop(965);
19174  return(GetModifiableRouteAt(15, x));
19175  }
19176  }
19177  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
19178 }
19179 
19180 // ---------------------------------------------------------------------------
19181 
19182 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
19183 {
19184  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
19185  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
19186  Utilities->SaveFileInt(OutFile, NextRouteID);
19187  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19188  {
19189  TOneRoute OneRoute = GetFixedRouteAt(165, x);
19190  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
19191  OneRoute.SavePrefDirVector(6, OutFile);
19192  }
19193  Utilities->CallLogPop(1442);
19194 }
19195 
19196 // ---------------------------------------------------------------------------
19197 
19198 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
19199 {
19200  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
19201  int NumberOfRoutes;
19202 
19203  NumberOfRoutes = Utilities->LoadFileInt(InFile);
19204  NextRouteID = Utilities->LoadFileInt(InFile);
19205  for(int x = 0; x < NumberOfRoutes; x++)
19206  {
19207  TOneRoute OneRoute; // empty route
19208  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
19209  OneRoute.LoadPrefDir(2, InFile);
19211  {
19212  StoreOneRouteAfterSessionLoad(0, &OneRoute);
19213  }
19214  else
19215  {
19216  Utilities->CallLogPop(1443);
19217  return(false);
19218  }
19219  }
19220  Utilities->CallLogPop(1444);
19221  return(true);
19222 }
19223 
19224 // ---------------------------------------------------------------------------
19225 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
19226 {
19227  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
19228  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
19229 
19230  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
19231  {
19232  Utilities->CallLogPop(1445);
19233  return(false);
19234  }
19235  int NextID = Utilities->LoadFileInt(InFile);
19236 
19237  if((NextID < 0) || (NextID > 1000000))
19238  {
19239  Utilities->CallLogPop(1446);
19240  return(false);
19241  }
19242  for(int x = 0; x < NumberOfRoutes; x++)
19243  {
19244  int RouteID = Utilities->LoadFileInt(InFile);
19245  if((RouteID < 0) || (RouteID > 20000))
19246  {
19247  Utilities->CallLogPop(1447);
19248  return(false);
19249  }
19250  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
19251  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
19252  {
19253  Utilities->CallLogPop(1448);
19254  return(false);
19255  }
19256  }
19257  Utilities->CallLogPop(1449);
19258  return(true);
19259 }
19260 
19261 // ---------------------------------------------------------------------------
19262 
19263 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
19264 {
19265  // return true for a loop
19266  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
19267  AnsiString(StartPosition));
19268  if(EndPosition == StartPosition)
19269  {
19270  Utilities->CallLogPop(1839);
19271  return(true); // shouldn't happen but treat as a loop if does
19272  }
19273 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
19274  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
19275  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
19276 
19277  while(TrackIsInARoute(15, TVPos, LkPos))
19278  {
19279  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
19280  int NewLkPos = -1;
19281  if(NewTVPos > -1)
19282  {
19283  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
19284  if(NewLkPos == -1)
19285  {
19286  Utilities->CallLogPop(1840);
19287  return(true); // shouldn't arise but treat as loop if does
19288  }
19289  }
19290  else // reached a buffer or continuation
19291  {
19292  Utilities->CallLogPop(1841);
19293  return(false);
19294  }
19295 //Error found by Xeon notified by email 13/10/20.
19296 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
19297 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
19298 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
19299 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
19300 //New check added for v2.6.0
19301 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
19302 //as possible in case there are other unforeseen effects.
19303  int RouteNumber; //dummy, not used
19304  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
19305  {
19306  Utilities->CallLogPop(2241);
19307  return(false);
19308  }
19309  //now make the connected element the current element, read across the TV number and determine the exit link
19310  TVPos = NewTVPos;
19311  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
19312  {
19313  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
19314  {
19315  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
19316  {
19317  LkPos = 1;
19318  }
19319  else
19320  {
19321  LkPos = 3;
19322  }
19323  }
19324  else
19325  {
19326  LkPos = 0;
19327  }
19328  }
19329  else
19330  {
19331  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
19332  }
19333  if(TVPos == StartPosition)
19334  {
19335  Utilities->CallLogPop(1842);
19336  return(true); // it is a loop
19337  }
19338  }
19339  Utilities->CallLogPop(1843);
19340  return(false); // reached end of route so not a loop
19341 }
19342 
19343 // ---------------------------------------------------------------------------
19344 
19345 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
19346 /*
19347  Track geometry allows diagonals to cross without occupying the same track element, so when
19348  route plotting it is necessary to check if there is an existing route or a train on such a crossing
19349  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
19350  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
19351  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
19352  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
19353  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
19354  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
19355  Each of these is examined in turn for each route element in the relevant position.
19356 
19357  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
19358  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
19359  that returns false in all cases (including elements & links not present) except train present.
19360 */
19361 {
19362  int TrainID; // not used in this function
19363 
19364  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
19365  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
19366  TPrefDirElement TempPrefDirElement;
19367  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
19368 
19369  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
19370  if(FirstPair.first > -1)
19371  {
19372  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
19373  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19374  {
19375  Utilities->CallLogPop(310);
19376  return(true);
19377  }
19378  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19379  {
19380  Utilities->CallLogPop(311);
19381  return(true);
19382  }
19383  }
19384  if(SecondPair.first > -1)
19385  {
19386  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
19387  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19388  {
19389  Utilities->CallLogPop(312);
19390  return(true);
19391  }
19392  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19393  {
19394  Utilities->CallLogPop(313);
19395  return(true);
19396  }
19397  }
19398  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
19399  9, TrainID)))
19400  {
19401  Utilities->CallLogPop(1997);
19402  return(true);
19403  }
19404  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
19405  if(FirstPair.first > -1)
19406  {
19407  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
19408  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19409  {
19410  Utilities->CallLogPop(314);
19411  return(true);
19412  }
19413  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19414  {
19415  Utilities->CallLogPop(315);
19416  return(true);
19417  }
19418  }
19419  if(SecondPair.first > -1)
19420  {
19421  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
19422  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19423  {
19424  Utilities->CallLogPop(316);
19425  return(true);
19426  }
19427  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19428  {
19429  Utilities->CallLogPop(317);
19430  return(true);
19431  }
19432  }
19433  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
19434  9, TrainID)))
19435  {
19436  Utilities->CallLogPop(1998);
19437  return(true);
19438  }
19439  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
19440  if(FirstPair.first > -1)
19441  {
19442  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
19443  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19444  {
19445  Utilities->CallLogPop(318);
19446  return(true);
19447  }
19448  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19449  {
19450  Utilities->CallLogPop(319);
19451  return(true);
19452  }
19453  }
19454  if(SecondPair.first > -1)
19455  {
19456  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
19457  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19458  {
19459  Utilities->CallLogPop(320);
19460  return(true);
19461  }
19462  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19463  {
19464  Utilities->CallLogPop(321);
19465  return(true);
19466  }
19467  }
19468  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
19469  7, TrainID)))
19470  {
19471  Utilities->CallLogPop(1999);
19472  return(true);
19473  }
19474  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
19475  if(FirstPair.first > -1)
19476  {
19477  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
19478  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19479  {
19480  Utilities->CallLogPop(322);
19481  return(true);
19482  }
19483  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19484  {
19485  Utilities->CallLogPop(323);
19486  return(true);
19487  }
19488  }
19489  if(SecondPair.first > -1)
19490  {
19491  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
19492  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19493  {
19494  Utilities->CallLogPop(324);
19495  return(true);
19496  }
19497  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19498  {
19499  Utilities->CallLogPop(325);
19500  return(true);
19501  }
19502  }
19503  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
19504  3, TrainID)))
19505  {
19506  Utilities->CallLogPop(2000);
19507  return(true);
19508  }
19509  Utilities->CallLogPop(326);
19510  return(false);
19511 }
19512 
19513 // ---------------------------------------------------------------------------
19514 
19515 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
19516 /*
19517  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
19518  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
19519  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
19520  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
19521  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
19522  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
19523  Each of these is examined in turn for each route element in the relevant position.
19524 */
19525 {
19526  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
19527  "," + AnsiString(DiagonalLinkNumber));
19528  TPrefDirElement TempPrefDirElement;
19529  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
19530 
19531  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
19532  if(FirstPair.first > -1)
19533  {
19534  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
19535  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19536  {
19537  Utilities->CallLogPop(2010);
19538  return(true);
19539  }
19540  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19541  {
19542  Utilities->CallLogPop(2011);
19543  return(true);
19544  }
19545  }
19546  if(SecondPair.first > -1)
19547  {
19548  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
19549  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19550  {
19551  Utilities->CallLogPop(2012);
19552  return(true);
19553  }
19554  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19555  {
19556  Utilities->CallLogPop(2013);
19557  return(true);
19558  }
19559  }
19560  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
19561  if(FirstPair.first > -1)
19562  {
19563  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
19564  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19565  {
19566  Utilities->CallLogPop(2014);
19567  return(true);
19568  }
19569  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19570  {
19571  Utilities->CallLogPop(2015);
19572  return(true);
19573  }
19574  }
19575  if(SecondPair.first > -1)
19576  {
19577  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
19578  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19579  {
19580  Utilities->CallLogPop(2016);
19581  return(true);
19582  }
19583  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19584  {
19585  Utilities->CallLogPop(2017);
19586  return(true);
19587  }
19588  }
19589  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
19590  if(FirstPair.first > -1)
19591  {
19592  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
19593  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19594  {
19595  Utilities->CallLogPop(2018);
19596  return(true);
19597  }
19598  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19599  {
19600  Utilities->CallLogPop(2019);
19601  return(true);
19602  }
19603  }
19604  if(SecondPair.first > -1)
19605  {
19606  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
19607  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19608  {
19609  Utilities->CallLogPop(2020);
19610  return(true);
19611  }
19612  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19613  {
19614  Utilities->CallLogPop(2021);
19615  return(true);
19616  }
19617  }
19618  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
19619  if(FirstPair.first > -1)
19620  {
19621  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
19622  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19623  {
19624  Utilities->CallLogPop(2022);
19625  return(true);
19626  }
19627  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19628  {
19629  Utilities->CallLogPop(2023);
19630  return(true);
19631  }
19632  }
19633  if(SecondPair.first > -1)
19634  {
19635  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
19636  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19637  {
19638  Utilities->CallLogPop(2024);
19639  return(true);
19640  }
19641  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19642  {
19643  Utilities->CallLogPop(2025);
19644  return(true);
19645  }
19646  }
19647  Utilities->CallLogPop(2026);
19648  return(false);
19649 }
19650 
19651 // ---------------------------------------------------------------------------
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:8686
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:691
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:477
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17760
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1284
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:931
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:464
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11428
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:677
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:744
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:627
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:579
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11401
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:432
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:566
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:81
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:353
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:889
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5535
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:12947
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:786
TFixedTrackPiece
Definition: TrackUnit.h:82
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:127
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1692
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:790
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:425
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:922
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:18356
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:91
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:805
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:246
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:923
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:9989
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:807
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:18766
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:934
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1338
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:509
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:782
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:595
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:716
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:13471
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:773
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:634
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:797
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:430
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:12987
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:693
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3686
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:714
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:395
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:454
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:895
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:780
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:281
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7235
TAllRoutes::TLockedRouteClass::TruncateTrackVectorPosition
unsigned int TruncateTrackVectorPosition
the TrackVector position of the element selected for truncation
Definition: TrackUnit.h:1609
TOneRoute::GetRouteTruncateElement
void GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:17272
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:467
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:53
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:698
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1672
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:711
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5687
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7136
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5714
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1494
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:586
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1633
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:66
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:840
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:861
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1928
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:934
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10323
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:616
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:17022
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:626
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:920
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:19515
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:432
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1663
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:607
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2824
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:484
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:551
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5867
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:742
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:686
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:460
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:150
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8163
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1504
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:645
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:18194
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:777
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:578
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:680
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:12726
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:360
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7621
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:483
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:401
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:9963
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9367
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:14119
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:15540
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:580
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:17720
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:18556
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:871
TTrack::NoPlatsMessageSent
bool NoPlatsMessageSent
used to send no platforms warning once only
Definition: TrackUnit.h:740
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:869
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:494
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1613
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:887
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:548
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:12530
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:157
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:513
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4455
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3662
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:687
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:845
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1516
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:459
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:596
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:774
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:466
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:810
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:7978
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:438
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:676
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:599
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1046
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4615
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1298
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6419
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:10812
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:668
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:517
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:882
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3538
Unused
@ Unused
Definition: TrackUnit.h:65
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:601
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:631
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1297
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:490
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:719
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:19030
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2857
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:784
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:222
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:19225
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:574
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9534
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1671
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1514
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1600
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:204
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:932
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:727
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:436
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:834
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3262
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:15705
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:222
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:791
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:683
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:500
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8430
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:12792
Simple
@ Simple
Definition: TrackUnit.h:65
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:784
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:444
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:45
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:478
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:808
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2873
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:713
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1020
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:18304
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:789
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:833
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:425
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1365
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:720
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:13043
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3859
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1734
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:609
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5827
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:684
TTrain
Definition: TrainUnit.h:304
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:376
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:13990
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:504
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:116
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:152
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11442
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:493
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:575
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:570
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:856
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:626
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7636
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:416
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:347
GapJump
@ GapJump
Definition: TrackUnit.h:65
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:443
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:804
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:18665
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:870
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7382
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:148
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:472
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:935
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:458
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:148
TTrack::Raising
@ Raising
Definition: TrackUnit.h:607
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:642
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:568
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10428
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:585
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:79
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1518
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1482
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:712
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:366
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:700
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:580
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:786
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:386
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:775
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:453
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:729
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1374
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:6079
End
@ End
Definition: TrackUnit.h:75
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1520
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:682
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:857
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:618
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:8784
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:878
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:918
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:563
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10537
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1033
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:299
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:814
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:726
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:71
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:792
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:592
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:928
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:124
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:737
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:492
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:772
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3833
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:1004
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:848
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:1005
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:226
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:442
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:525
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:715
SignalPost
@ SignalPost
Definition: TrackUnit.h:65
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9499
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1014
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:462
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:17708
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:502
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:792
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1091
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1637
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:806
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:841
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7650
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:457
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:667
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:404
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6828
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:643
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:224
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:491
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:699
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:36
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8823
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:921
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:831
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:17693
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:770
Concourse
@ Concourse
Definition: TrackUnit.h:66
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:586
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:671
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:801
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:815
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:74
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:13760
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:13497
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:230
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:728
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:901
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:64
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:503
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4540
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1878
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:428
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:828
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:434
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:843
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:481
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:608
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:818
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:430
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:495
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:766
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:473
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:93
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:431
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:830
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:589
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:11015
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:18509
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4774
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:157
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1897
TTrack::MultiplayerOverlayMap
TMultiplayerOverlayMap MultiplayerOverlayMap
Definition: TrackUnit.h:774
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:688
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:803
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:939
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:742
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:558
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:91
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:600
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:734
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:849
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:464
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:652
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11260
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:19131
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:586
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1031
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:625
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2841
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:724
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1526
TTrack::ResetAllTrainIDElements
void ResetAllTrainIDElements(int Caller)
Track elements have members that indicates whether and on what track a train is present (TrainIDOnEle...
Definition: TrackUnit.cpp:7607
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:14936
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7263
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8620
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7342
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:681
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:735
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5738
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:689
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:674
TUtilities::CallLogPop
void CallLogPop(int Caller)
< specifies whether no delays or minor, moderate or major random delays are to be applied
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:317
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:680
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1300
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:848
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:817
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:510
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:816
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:470
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:13131
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:780
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:881
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:12266
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1638
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1690
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:45
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:919
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:602
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:12759
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:666
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:17480
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3639
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:169
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:13450
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11303
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:10678
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1780
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:778
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:913
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:496
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:577
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:5921
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1029
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12579
Under
@ Under
Definition: TrackUnit.h:75
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:450
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller) const
Called by GetNextNonPreferredRouteElement and GetNextPreferredRouteElement to check whether or not an...
Definition: TrackUnit.cpp:16990
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:801
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:710
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:622
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:155
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2896
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11454
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:11774
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:885
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:427
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:134
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:10572
Lead
@ Lead
Definition: TrackUnit.h:75
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5786
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1814
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13698
TTrack::PlotContinuation
void PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a continuation on screen, may have overlays if a multiplayer session.
Definition: TrackUnit.cpp:5998
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:867
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:555
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5578
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6400
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:85
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1329
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9295
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:468
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:469
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:593
TTrack::Up
@ Up
Definition: TrackUnit.h:607
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:877
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:803
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:581
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:10551
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:938
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1476
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:378
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8587
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1631
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:738
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:200
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:17547
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1620
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:363
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:795
Crossover
@ Crossover
Definition: TrackUnit.h:65
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6286
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:475
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:446
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:805
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:637
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8533
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:797
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7291
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:9962
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:452
Signal
@ Signal
Definition: TrackUnit.h:75
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:568
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:586
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:461
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:772
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17997
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:152
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1548
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12629
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:506
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:11199
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4624
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:566
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10523
TGraphicElement::Width
int Width
Definition: TrackUnit.h:434
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:18905
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:520
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:19115
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:17823
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:778
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:488
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:793
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:584
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:656
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:447
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or ' ' (CRLF) accepted as delimiters), returns true for succes...
Definition: Utilities.cpp:529
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:785
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14528
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:654
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4141
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2359
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:687
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:465
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9435
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:12397
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:603
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:407
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:876
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:940
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5762
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:19198
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:582
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1518
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:925
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:783
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1507
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:842
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6989
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:471
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:744
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1044
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1046
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:514
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:7822
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:17639
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:655
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:422
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7364
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:799
Erase
@ Erase
Definition: TrackUnit.h:66
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:846
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:398
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:480
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5383
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:801
TAllRoutes::LockedRouteTruncateTrackVectorPosition
unsigned int LockedRouteTruncateTrackVectorPosition
Definition: TrackUnit.h:1670
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:826
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:873
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:590
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:13520
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:614
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:11111
Parapet
@ Parapet
Definition: TrackUnit.h:66
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:448
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:17666
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:72
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:800
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:1008
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:269
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:9104
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:17612
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:378
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:866
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:801
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:18532
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:605
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:930
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
< map of coupled continuations
Definition: TrackUnit.h:776
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:798
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:146
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:479
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:821
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:247
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:550
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1049
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:721
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:813
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:15139
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:838
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:136
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:202
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:11331
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:12324
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:505
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1278
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:497
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:17575
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:611
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:476
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:746
TTrack
Definition: TrackUnit.h:544
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1337
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:848
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1368
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:18681
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1607
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8132
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:635
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:584
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:855
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:665
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:741
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:864
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:127
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:820
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:516
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:700
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:200
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:18172
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:208
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2976
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:451
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:9228
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:924
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6180
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2111
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:583
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:739
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:157
TTrackElement::TTrackElement
TTrackElement()
Constructor for non-specific default element. Use high neg numbers for 'unset' h & v as can go high n...
Definition: TrackUnit.h:163
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:859
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:784
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2577
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:198
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1605
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7786
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:482
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:12112
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:12890
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:582
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1482
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:10460
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8496
IDInt
Definition: TrackUnit.h:493
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2535
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:588
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:19166
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:612
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:793
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4428
TDisplay
Definition: DisplayUnit.h:48
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10210
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:5128
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:144
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:866
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:787
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:836
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:436
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:19263
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1126
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9218
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:141
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:566
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:96
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7733
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1279
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:227
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:152
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:901
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:13200
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:762
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:745
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:381
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:646
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:206
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:393
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:862
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:14324
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1675
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:129
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:782
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7701
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:628
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:823
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:796
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:730
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:146
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:883
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:769
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1493
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:853
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1611
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:850
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1621
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:437
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4696
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:585
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:9044
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:706
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:15511
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1307
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:731
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:430
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13626
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:827
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1285
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:13401
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:150
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:717
Points
@ Points
Definition: TrackUnit.h:65
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:738
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:18245
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:868
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:9893
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:11182
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:410
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:597
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:835
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:499
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4163
Trail
@ Trail
Definition: TrackUnit.h:75
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:17524
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9277
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:17109
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:776
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1850
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:498
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:819
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:16927
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:832
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:662
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:419
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:740
Continuation
@ Continuation
Definition: TrackUnit.h:65
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1040
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7580
GraphicUnit.h
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3739
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:6018
TOnePrefDir::FindLinkingCompatiblePrefDir
bool FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that is compatible and links to another element at given vector number and l...
Definition: TrackUnit.cpp:13298
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:87
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:586
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:356
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9324
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:867
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:875
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:883
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:12155
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:572
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:837
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:767
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:872
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:430
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:14972
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:586
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1029
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3356
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:434
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:888
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1510
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:87
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:456
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:703
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:673
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:723
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1669
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:926
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:369
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:263
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:743
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:851
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:19345
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:487
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:13095
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1018
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:485
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:781
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1484
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1022
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:85
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:350
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:449
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:768
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:630
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:877
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4681
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:886
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:18143
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1702
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8634
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:713
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:691
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:591
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:788
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:667
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:10969
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:825
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:702
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1339
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:19182
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:576
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1860
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4666
Connection
@ Connection
Definition: TrackUnit.h:75
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3716
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:359
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1677
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:9556
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:1009
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:747
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:501
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:16740
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:11973
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:721
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:824
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8560
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:874
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1027
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:18454
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:18410
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:7062
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:561
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:10840
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:706
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:865
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:717
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1366
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:898
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:486
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5806
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:858
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:722
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:445
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:261
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:430
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:752
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:10016
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:568
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:719
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:730
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:17680
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4806
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:802
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2752
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:689
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7661
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:387
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3118
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:375
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:854
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:131
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:879
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:372
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:16898
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:624
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:77
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:13890
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:313
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:349
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:750
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:604
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:688
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:628
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:394
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:489
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1279
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:649
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:463
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:659
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:914
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:639
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11533
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:455
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:430
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:515
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:933
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:99
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1480
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:195
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8683
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:812
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1758
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:8865
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:640
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:586
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:707
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:13597
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:19150
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:140
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:606
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1336
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4259
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:794
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4557
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7524
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1955
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:526
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1035
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6326
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:1006
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:709
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:65
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:839
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:641
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7319
Platform
@ Platform
Definition: TrackUnit.h:65
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1368
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:208
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:661
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:884
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:756
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:702
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4582
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:770
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1615
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1042
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:779
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:936
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8083
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:679
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1292
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:809
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:844
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9473
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1016
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:768
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:11076
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1765
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:829
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:63
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:638
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1482
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:348
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:15932
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7507
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:796
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:148
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:794
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:692
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1484
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:611
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6343
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:723
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3616
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:771
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:657
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TTrack::DefaultTrackSpeedLimit
int DefaultTrackSpeedLimit
speed limit of each track element before being changed within the program (can be changed in config....
Definition: TrackUnit.h:760
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:579
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:801
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:736
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:11002
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:788
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:880
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:848
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:148
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: TrackUnit.h:40
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:675
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:927
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:299
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:708
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:620
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:727
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:83
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1074
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:413
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:581
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:89
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:16306
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:682
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:799
RouteCall
@ RouteCall
Definition: TrackUnit.h:1285
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:388
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11467
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:860
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:606
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:502
NotSet
@ NotSet
Definition: TrackUnit.h:75
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:665
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:18726
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:89
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:261
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:391
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:607
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:594
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:11031
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:10292
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:670
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:533
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:198
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:790
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:929
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6244
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:157
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:66
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:937
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:728
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11479
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1341
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:392
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:142
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1530
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:852
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:736
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:822
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:707
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:568
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:629
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10283
Bridge
@ Bridge
Definition: TrackUnit.h:65
TTrack::DefaultTrackLength
int DefaultTrackLength
length of each track element before being changed within the program (can be changed in config....
Definition: TrackUnit.h:758
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:863
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:440
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1279
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:811
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:524
Gap
@ Gap
Definition: TrackUnit.h:75
Buffers
@ Buffers
Definition: TrackUnit.h:65
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:16656
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:704
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:55
CrossConn
@ CrossConn
Definition: TrackUnit.h:75
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11491
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:474
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4494
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:11414
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:847